home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / ATL / include / Atldb.h < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  189.1 KB  |  6,183 lines

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10.  
  11. #ifndef __ATLDB_H
  12. #define __ATLDB_H
  13.  
  14. // OLE DB Provider Support
  15.  
  16. // Interface Impl Classes
  17. //
  18. // Data Source Object
  19. //
  20. // -Mandatory Interfaces:
  21. //    IDBCreateSession
  22. //    IDBInitialize
  23. //    IDBProperties
  24. //    IPersist
  25. //
  26. // Session Object
  27. //
  28. // -Mandatory Interfaces:
  29. //    IGetDataSource
  30. //    IOpenRowset
  31. //    ISessionProperties
  32. //
  33. // -Optional Interfaces:
  34. //    IDBCreateCommand
  35. //    IDBSchemaRowset
  36. //
  37. // Rowset Object
  38. //
  39. // -Mandatory Interfaces:
  40. //    IAccessor
  41. //    IColumnsInfo
  42. //    IConvertType
  43. //    IRowset
  44. //    IRowsetInfo
  45. //
  46. // -Optional Interfaces:
  47. //    IRowsetIdentity
  48. //
  49. // Command Object
  50. //
  51. // -Mandatory Interfaces:
  52. // ICommand)
  53. // IAccessor)
  54. // ICommandProperties
  55. // ICommandText - derives from ICommand
  56. // IColumnsInfo
  57. // IConvertType
  58.  
  59. #include <oledb.h>
  60. #include <limits.h>
  61. #include <oledberr.h>
  62. #include <msdadc.h>
  63. #include <atldbcli.h>
  64.  
  65. //Forwards 
  66. template <class T> class CUtlPropInfo;
  67. class CColumnIds;
  68.  
  69. // Additional Property Flag needed internally
  70. const int    DBPROPFLAGS_CHANGE    = 0x40000000;
  71.  
  72. // -------------  STRUCTURE DEFINITIONS --------------------------------
  73.  
  74. struct UPROPVAL
  75. {
  76.     DBPROPOPTIONS    dwOption;
  77.     CColumnIds*        pCColumnIds;
  78.     DWORD            dwFlags;
  79.     VARIANT            vValue;
  80. };
  81.  
  82. struct UPROPINFO
  83. {
  84.     DBPROPID    dwPropId;
  85.     ULONG        ulIDS;
  86.     VARTYPE        VarType;
  87.     DBPROPFLAGS    dwFlags;
  88.     union
  89.     {
  90.         DWORD dwVal;
  91.         LPOLESTR szVal;
  92.     };
  93.     DBPROPOPTIONS dwOption;
  94. };
  95.  
  96. struct UPROP
  97. {
  98.     ULONG            cPropIds;
  99.     UPROPINFO**        rgpUPropInfo;
  100.     UPROPVAL*        pUPropVal;
  101. };
  102.  
  103. struct PROPCOLID
  104. {
  105.     DBID            dbidProperty;    // The column id information
  106.     DBPROPOPTIONS    dwOption;        
  107.     VARIANT            vValue;
  108. };
  109.  
  110. typedef PROPCOLID* PPROPCOLID;
  111.  
  112. struct UPROPSET
  113. {
  114.     const GUID* pPropSet;
  115.     ULONG cUPropInfo;
  116.     UPROPINFO* pUPropInfo;
  117.     DWORD dwFlags;
  118. };
  119.  
  120. struct ATLBINDINGS
  121. {
  122.     DBBINDING* pBindings;
  123.     DWORD dwRef;
  124.     ULONG cBindings;
  125.     DBACCESSORFLAGS dwAccessorFlags;
  126. };
  127.  
  128. struct ATLCOLUMNINFO
  129. {
  130.     LPOLESTR pwszName;
  131.     ITypeInfo *pTypeInfo;
  132.     ULONG iOrdinal;
  133.     DBCOLUMNFLAGS dwFlags;
  134.     ULONG ulColumnSize;
  135.     DBTYPE wType;
  136.     BYTE bPrecision;
  137.     BYTE bScale;
  138.     DBID columnid;
  139.     UINT cbOffset;
  140. };
  141.  
  142. //
  143. // The following very large sections of defines are to implement auto determination
  144. // of Preoperty map constants based on a stringized prop name.  There is one set for
  145. // Type (VT_), one for Init Value, and one for Property flags.
  146. //
  147.  
  148. #define ABORTPRESERVE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  149. #define ACTIVESESSIONS_Flags  ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  150. #define APPENDONLY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  151. #define ASYNCTXNABORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  152. #define ASYNCTXNCOMMIT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  153. #define AUTH_CACHE_AUTHINFO_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  154. #define AUTH_ENCRYPT_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  155. #define AUTH_INTEGRATED_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  156. #define AUTH_MASK_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  157. #define AUTH_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  158. #define AUTH_PERSIST_ENCRYPTED_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  159. #define AUTH_PERSIST_SENSITIVE_AUTHINFO_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  160. #define AUTH_USERID_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  161. #define BLOCKINGSTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  162. #define BOOKMARKS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  163. #define BOOKMARKSKIPPED_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  164. #define BOOKMARKTYPE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  165. #define BYREFACCESSORS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  166. #define CACHEDEFERRED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  167. #define CANFETCHBACKWARDS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  168. #define CANHOLDROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  169. #define CANSCROLLBACKWARDS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  170. #define CATALOGLOCATION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  171. #define CATALOGTERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  172. #define CATALOGUSAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  173. #define CHANGEINSERTEDROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_CHANGE )
  174. #define COL_AUTOINCREMENT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  175. #define COL_DEFAULT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  176. #define COL_DESCRIPTION_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  177. #define COL_FIXEDLENGTH_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  178. #define COL_NULLABLE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  179. #define COL_PRIMARYKEY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  180. #define COL_UNIQUE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  181. #define COLUMNDEFINITION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
  182. #define COLUMNRESTRICT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  183. #define COMMANDTIMEOUT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  184. #define COMMITPRESERVE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  185. #define CONCATNULLBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  186. #define CURRENTCATALOG_Flags ( DBPROPFLAGS_DATASOURCE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  187. #define DATASOURCENAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  188. #define DATASOURCEREADONLY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  189. #define DBMSNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  190. #define DBMSVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  191. #define DEFERRED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  192. #define DELAYSTORAGEOBJECTS_Flags  ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  193. #define DSOTHREADMODEL_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  194. #define GROUPBY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  195. #define HETEROGENEOUSTABLES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  196. #define IAccessor_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  197. #define IColumnsInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  198. #define IColumnsRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  199. #define IConnectionPointContainer_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  200. #define IConvertType_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  201. #define IRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  202. #define IRowsetChange_Flags  ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  203. #define IRowsetIdentity_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  204. #define IRowsetIndex_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  205. #define IRowsetInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  206. #define IRowsetLocate_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  207. #define IRowsetResynch_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  208. #define IRowsetScroll_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  209. #define IRowsetUpdate_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  210. #define ISupportErrorInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  211. #define ILockBytes_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  212. #define ISequentialStream_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
  213. #define IStorage_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  214. #define IStream_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  215. #define IDENTIFIERCASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  216. #define IMMOBILEROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  217. #define INDEX_AUTOUPDATE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  218. #define INDEX_CLUSTERED_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  219. #define INDEX_FILLFACTOR_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  220. #define INDEX_INITIALSIZE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  221. #define INDEX_NULLCOLLATION_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  222. #define INDEX_NULLS_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  223. #define INDEX_PRIMARYKEY_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  224. #define INDEX_SORTBOOKMARKS_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  225. #define INDEX_TEMPINDEX_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  226. #define INDEX_TYPE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  227. #define INDEX_UNIQUE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  228. #define INIT_DATASOURCE_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  229. #define INIT_HWND_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  230. #define INIT_IMPERSONATION_LEVEL_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  231. #define INIT_LCID_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  232. #define INIT_LOCATION_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  233. #define INIT_MODE_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  234. #define INIT_PROMPT_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  235. #define INIT_PROTECTION_LEVEL_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  236. #define INIT_PROVIDERSTRING_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  237. #define INIT_TIMEOUT_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  238. #define LITERALBOOKMARKS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  239. #define LITERALIDENTITY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  240. #define MAXINDEXSIZE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  241. #define MAXOPENROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  242. #define MAXPENDINGROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  243. #define MAXROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  244. #define MAXROWSIZE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  245. #define MAXROWSIZEINCLUDESBLOB_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  246. #define MAXTABLESINSELECT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  247. #define MAYWRITECOLUMN_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  248. #define MEMORYUSAGE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  249. #define MULTIPLEPARAMSETS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  250. #define MULTIPLERESULTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  251. #define MULTIPLESTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  252. #define MULTITABLEUPDATE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  253. #define NOTIFICATIONPHASES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  254. #define NOTIFYCOLUMNSET_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  255. #define NOTIFYROWDELETE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  256. #define NOTIFYROWFIRSTCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  257. #define NOTIFYROWINSERT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  258. #define NOTIFYROWRESYNCH_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  259. #define NOTIFYROWSETRELEASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  260. #define NOTIFYROWSETFETCHPOSITIONCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  261. #define NOTIFYROWUNDOCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  262. #define NOTIFYROWUNDODELETE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  263. #define NOTIFYROWUNDOINSERT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  264. #define NOTIFYROWUPDATE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  265. #define NULLCOLLATION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  266. #define OLEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  267. #define ORDERBYCOLUMNSINSELECT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  268. #define ORDEREDBOOKMARKS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  269. #define OTHERINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  270. #define OTHERUPDATEDELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  271. #define OUTPUTPARAMETERAVAILABILITY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  272. #define OWNINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  273. #define OWNUPDATEDELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  274. #define PERSISTENTIDTYPE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  275. #define PREPAREABORTBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  276. #define PREPARECOMMITBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  277. #define PROCEDURETERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  278. #define PROVIDERNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  279. #define PROVIDEROLEDBVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  280. #define PROVIDERVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  281. #define QUICKRESTART_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  282. #define QUOTEDIDENTIFIERCASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  283. #define REENTRANTEVENTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  284. #define REMOVEDELETED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  285. #define REPORTMULTIPLECHANGES_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_CHANGE ) 
  286. #define RETURNPENDINGINSERTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  287. #define ROWRESTRICT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  288. #define ROWSETCONVERSIONSONCOMMAND_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  289. #define ROWTHREADMODEL_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  290. #define SCHEMATERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  291. #define SCHEMAUSAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  292. #define SERVERCURSOR_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  293. #define SESS_AUTOCOMMITISOLEVELS_Flags ( DBPROPFLAGS_SESSION | DBPROPFLAGS_READ ) 
  294. #define SQLSUPPORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  295. #define STRONGIDENTITY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  296. #define STRUCTUREDSTORAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  297. #define SUBQUERIES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  298. #define SUPPORTEDTXNDDL_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  299. #define SUPPORTEDTXNISOLEVELS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  300. #define SUPPORTEDTXNISORETAIN_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  301. #define TABLETERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  302. #define TBL_TEMPTABLE_Flags ( DBPROPFLAGS_TABLE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) 
  303. #define TRANSACTEDOBJECT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) 
  304. #define UPDATABILITY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
  305. #define USERNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) 
  306.  
  307.  
  308.  
  309. #define ABORTPRESERVE_Type VT_BOOL 
  310. #define ACTIVESESSIONS_Type VT_I4 
  311. #define APPENDONLY_Type VT_BOOL 
  312. #define ASYNCTXNABORT_Type VT_BOOL 
  313. #define ASYNCTXNCOMMIT_Type VT_BOOL 
  314. #define AUTH_CACHE_AUTHINFO_Type VT_BOOL 
  315. #define AUTH_ENCRYPT_PASSWORD_Type VT_BOOL 
  316. #define AUTH_INTEGRATED_Type VT_BSTR 
  317. #define AUTH_MASK_PASSWORD_Type VT_BOOL 
  318. #define AUTH_PASSWORD_Type VT_BSTR 
  319. #define AUTH_PERSIST_ENCRYPTED_Type VT_BOOL 
  320. #define AUTH_PERSIST_SENSITIVE_AUTHINFO_Type VT_BOOL
  321. #define AUTH_USERID_Type VT_BSTR 
  322. #define BLOCKINGSTORAGEOBJECTS_Type VT_BOOL 
  323. #define BOOKMARKS_Type VT_BOOL 
  324. #define BOOKMARKSKIPPED_Type VT_BOOL 
  325. #define BOOKMARKTYPE_Type VT_I4 
  326. #define BYREFACCESSORS_Type VT_BOOL 
  327. #define CACHEDEFERRED_Type VT_BOOL 
  328. #define CANFETCHBACKWARDS_Type VT_BOOL 
  329. #define CANHOLDROWS_Type VT_BOOL 
  330. #define CANSCROLLBACKWARDS_Type VT_BOOL 
  331. #define CATALOGLOCATION_Type VT_I4 
  332. #define CATALOGTERM_Type VT_BSTR 
  333. #define CATALOGUSAGE_Type VT_I4 
  334. #define CHANGEINSERTEDROWS_Type VT_BOOL 
  335. #define COL_AUTOINCREMENT_Type VT_BOOL 
  336. #define COL_DEFAULT_Type VT_BSTR 
  337. #define COL_DESCRIPTION_Type VT_BSTR 
  338. #define COL_FIXEDLENGTH_Type VT_BOOL 
  339. #define COL_NULLABLE_Type VT_BOOL 
  340. #define COL_PRIMARYKEY_Type VT_BOOL 
  341. #define COL_UNIQUE_Type VT_BOOL 
  342. #define COLUMNDEFINITION_Type VT_I4 
  343. #define COLUMNRESTRICT_Type VT_BOOL 
  344. #define COMMANDTIMEOUT_Type VT_I4 
  345. #define COMMITPRESERVE_Type VT_BOOL 
  346. #define CONCATNULLBEHAVIOR_Type VT_I4 
  347. #define CURRENTCATALOG_Type VT_BSTR 
  348. #define DATASOURCENAME_Type VT_BSTR 
  349. #define DATASOURCEREADONLY_Type VT_BOOL 
  350. #define DBMSNAME_Type VT_BSTR 
  351. #define DBMSVER_Type VT_BSTR 
  352. #define DEFERRED_Type VT_BOOL
  353. #define DELAYSTORAGEOBJECTS_Type VT_BOOL 
  354. #define DSOTHREADMODEL_Type VT_I4 
  355. #define GROUPBY_Type VT_I4 
  356. #define HETEROGENEOUSTABLES_Type VT_I4
  357. #define IAccessor_Type VT_BOOL 
  358. #define IColumnsInfo_Type VT_BOOL 
  359. #define IColumnsRowset_Type VT_BOOL 
  360. #define IConnectionPointContainer_Type VT_BOOL 
  361. #define IConvertType_Type VT_BOOL 
  362. #define IRowset_Type VT_BOOL 
  363. #define IRowsetChange_Type VT_BOOL 
  364. #define IRowsetIdentity_Type VT_BOOL 
  365. #define IRowsetIndex_Type VT_BOOL 
  366. #define IRowsetInfo_Type VT_BOOL 
  367. #define IRowsetLocate_Type VT_BOOL 
  368. #define IRowsetResynch_Type VT_BOOL 
  369. #define IRowsetScroll_Type VT_BOOL 
  370. #define IRowsetUpdate_Type VT_BOOL 
  371. #define ISupportErrorInfo_Type VT_BOOL 
  372. #define ILockBytes_Type VT_BOOL 
  373. #define ISequentialStream_Type VT_BOOL 
  374. #define IStorage_Type VT_BOOL 
  375. #define IStream_Type VT_BOOL 
  376. #define IDENTIFIERCASE_Type VT_I4 
  377. #define IMMOBILEROWS_Type VT_BOOL 
  378. #define INDEX_AUTOUPDATE_Type VT_BOOL 
  379. #define INDEX_CLUSTERED_Type VT_BOOL 
  380. #define INDEX_FILLFACTOR_Type VT_I4 
  381. #define INDEX_INITIALSIZE_Type VT_I4 
  382. #define INDEX_NULLCOLLATION_Type VT_I4 
  383. #define INDEX_NULLS_Type VT_I4 
  384. #define INDEX_PRIMARYKEY_Type VT_BOOL 
  385. #define INDEX_SORTBOOKMARKS_Type VT_BOOL 
  386. #define INDEX_TEMPINDEX_Type VT_BOOL 
  387. #define INDEX_TYPE_Type VT_I4 
  388. #define INDEX_UNIQUE_Type VT_BOOL 
  389. #define INIT_DATASOURCE_Type VT_BSTR 
  390. #define INIT_HWND_Type VT_I4 
  391. #define INIT_IMPERSONATION_LEVEL_Type VT_I4 
  392. #define INIT_LCID_Type VT_I4 
  393. #define INIT_LOCATION_Type VT_BSTR 
  394. #define INIT_MODE_Type VT_I4 
  395. #define INIT_PROMPT_Type VT_I2 
  396. #define INIT_PROTECTION_LEVEL_Type VT_I4 
  397. #define INIT_PROVIDERSTRING_Type VT_BSTR 
  398. #define INIT_TIMEOUT_Type VT_I4 
  399. #define LITERALBOOKMARKS_Type VT_BOOL 
  400. #define LITERALIDENTITY_Type VT_BOOL 
  401. #define MAXINDEXSIZE_Type VT_I4 
  402. #define MAXOPENROWS_Type VT_I4 
  403. #define MAXPENDINGROWS_Type VT_I4 
  404. #define MAXROWS_Type VT_I4 
  405. #define MAXROWSIZE_Type VT_I4
  406. #define MAXROWSIZEINCLUDESBLOB_Type VT_BOOL 
  407. #define MAXTABLESINSELECT_Type VT_I4 
  408. #define MAYWRITECOLUMN_Type VT_BOOL 
  409. #define MEMORYUSAGE_Type VT_I4 
  410. #define MULTIPLEPARAMSETS_Type VT_BOOL 
  411. #define MULTIPLERESULTS_Type VT_I4 
  412. #define MULTIPLESTORAGEOBJECTS_Type VT_BOOL  
  413. #define MULTITABLEUPDATE_Type VT_BOOL 
  414. #define NOTIFICATIONPHASES_Type VT_I4 
  415. #define NOTIFYCOLUMNSET_Type VT_I4 
  416. #define NOTIFYROWDELETE_Type VT_I4 
  417. #define NOTIFYROWFIRSTCHANGE_Type VT_I4 
  418. #define NOTIFYROWINSERT_Type VT_I4 
  419. #define NOTIFYROWRESYNCH_Type VT_I4 
  420. #define NOTIFYROWSETRELEASE_Type VT_I4 
  421. #define NOTIFYROWSETFETCHPOSITIONCHANGE_Type VT_I4 
  422. #define NOTIFYROWUNDOCHANGE_Type VT_I4 
  423. #define NOTIFYROWUNDODELETE_Type VT_I4 
  424. #define NOTIFYROWUNDOINSERT_Type VT_I4 
  425. #define NOTIFYROWUPDATE_Type VT_I4 
  426. #define NULLCOLLATION_Type VT_I4 
  427. #define OLEOBJECTS_Type VT_I4
  428. #define ORDERBYCOLUMNSINSELECT_Type VT_BOOL 
  429. #define ORDEREDBOOKMARKS_Type VT_BOOL 
  430. #define OTHERINSERT_Type VT_BOOL 
  431. #define OTHERUPDATEDELETE_Type VT_BOOL
  432. #define OUTPUTPARAMETERAVAILABILITY_Type VT_I4 
  433. #define OWNINSERT_Type VT_BOOL 
  434. #define OWNUPDATEDELETE_Type VT_BOOL 
  435. #define PERSISTENTIDTYPE_Type VT_I4 
  436. #define PREPAREABORTBEHAVIOR_Type VT_I4 
  437. #define PREPARECOMMITBEHAVIOR_Type VT_I4 
  438. #define PROCEDURETERM_Type VT_BSTR 
  439. #define PROVIDERNAME_Type VT_BSTR 
  440. #define PROVIDEROLEDBVER_Type VT_BSTR 
  441. #define PROVIDERVER_Type VT_BSTR 
  442. #define QUICKRESTART_Type VT_BOOL 
  443. #define QUOTEDIDENTIFIERCASE_Type VT_I4 
  444. #define REENTRANTEVENTS_Type VT_BOOL 
  445. #define REMOVEDELETED_Type VT_BOOL 
  446. #define REPORTMULTIPLECHANGES_Type VT_BOOL 
  447. #define RETURNPENDINGINSERTS_Type VT_BOOL 
  448. #define ROWRESTRICT_Type VT_BOOL 
  449. #define ROWSETCONVERSIONSONCOMMAND_Type VT_BOOL 
  450. #define ROWTHREADMODEL_Type VT_I4 
  451. #define SCHEMATERM_Type VT_BSTR 
  452. #define SCHEMAUSAGE_Type VT_I4 
  453. #define SERVERCURSOR_Type VT_BOOL
  454. #define SESS_AUTOCOMMITISOLEVELS_Type VT_I4 
  455. #define SQLSUPPORT_Type VT_I4 
  456. #define STRONGIDENTITY_Type VT_BOOL 
  457. #define STRUCTUREDSTORAGE_Type VT_I4 
  458. #define SUBQUERIES_Type VT_I4 
  459. #define SUPPORTEDTXNDDL_Type VT_I4 
  460. #define SUPPORTEDTXNISOLEVELS_Type VT_I4 
  461. #define SUPPORTEDTXNISORETAIN_Type VT_I4 
  462. #define TABLETERM_Type VT_BSTR 
  463. #define TBL_TEMPTABLE_Type VT_BOOL 
  464. #define TRANSACTEDOBJECT_Type VT_BOOL 
  465. #define UPDATABILITY_Type VT_I4 
  466. #define USERNAME_Type VT_BSTR 
  467.  
  468.  
  469.  
  470. #define ABORTPRESERVE_Value VARIANT_FALSE 
  471. #define ACTIVESESSIONS_Value 0 
  472. #define APPENDONLY_Value VARIANT_FALSE 
  473. #define ASYNCTXNABORT_Value VARIANT_FALSE 
  474. #define ASYNCTXNCOMMIT_Value VARIANT_FALSE 
  475. #define AUTH_CACHE_AUTHINFO_Value VARIANT_FALSE 
  476. #define AUTH_ENCRYPT_PASSWORD_Value VARIANT_FALSE 
  477. #define AUTH_INTEGRATED_Value OLESTR("") 
  478. #define AUTH_MASK_PASSWORD_Value VARIANT_FALSE 
  479. #define AUTH_PASSWORD_Value OLESTR("") 
  480. #define AUTH_PERSIST_ENCRYPTED_Value VARIANT_FALSE 
  481. #define AUTH_PERSIST_SENSITIVE_AUTHINFO_Value VARIANT_FALSE
  482. #define AUTH_USERID_Value OLESTR("") 
  483. #define BLOCKINGSTORAGEOBJECTS_Value VARIANT_FALSE 
  484. #define BOOKMARKS_Value VARIANT_FALSE 
  485. #define BOOKMARKSKIPPED_Value VARIANT_FALSE 
  486. #define BOOKMARKTYPE_Value 0 
  487. #define BYREFACCESSORS_Value VARIANT_FALSE 
  488. #define CACHEDEFERRED_Value VARIANT_FALSE 
  489. #define CANFETCHBACKWARDS_Value VARIANT_TRUE 
  490. #define CANHOLDROWS_Value VARIANT_TRUE 
  491. #define CANSCROLLBACKWARDS_Value VARIANT_TRUE 
  492. #define CATALOGLOCATION_Value 0 
  493. #define CATALOGTERM_Value OLESTR("") 
  494. #define CATALOGUSAGE_Value 0 
  495. #define CHANGEINSERTEDROWS_Value VARIANT_FALSE 
  496. #define COL_AUTOINCREMENT_Value VARIANT_FALSE 
  497. #define COL_DEFAULT_Value OLESTR("") 
  498. #define COL_DESCRIPTION_Value OLESTR("") 
  499. #define COL_FIXEDLENGTH_Value VARIANT_FALSE 
  500. #define COL_NULLABLE_Value VARIANT_FALSE 
  501. #define COL_PRIMARYKEY_Value VARIANT_FALSE 
  502. #define COL_UNIQUE_Value VARIANT_FALSE 
  503. #define COLUMNDEFINITION_Value 0 
  504. #define COLUMNRESTRICT_Value VARIANT_FALSE 
  505. #define COMMANDTIMEOUT_Value 0 
  506. #define COMMITPRESERVE_Value VARIANT_FALSE 
  507. #define CONCATNULLBEHAVIOR_Value 0 
  508. #define CURRENTCATALOG_Value OLESTR("") 
  509. #define DATASOURCENAME_Value OLESTR("") 
  510. #define DATASOURCEREADONLY_Value VARIANT_FALSE 
  511. #define DBMSNAME_Value OLESTR("") 
  512. #define DBMSVER_Value OLESTR("") 
  513. #define DEFERRED_Value VARIANT_FALSE
  514. #define DELAYSTORAGEOBJECTS_Value VARIANT_FALSE 
  515. #define DSOTHREADMODEL_Value DBPROPVAL_RT_APTMTTHREAD 
  516. #define GROUPBY_Value 0 
  517. #define HETEROGENEOUSTABLES_Value 0
  518. #define IAccessor_Value VARIANT_TRUE 
  519. #define IColumnsInfo_Value VARIANT_TRUE 
  520. #define IColumnsRowset_Value VARIANT_FALSE 
  521. #define IConnectionPointContainer_Value VARIANT_FALSE 
  522. #define IConvertType_Value VARIANT_TRUE 
  523. #define IRowset_Value VARIANT_TRUE 
  524. #define IRowsetChange_Value VARIANT_FALSE 
  525. #define IRowsetIdentity_Value VARIANT_TRUE 
  526. #define IRowsetIndex_Value VARIANT_FALSE 
  527. #define IRowsetInfo_Value VARIANT_TRUE 
  528. #define IRowsetLocate_Value VARIANT_FALSE 
  529. #define IRowsetResynch_Value VARIANT_FALSE 
  530. #define IRowsetScroll_Value VARIANT_FALSE 
  531. #define IRowsetUpdate_Value VARIANT_FALSE 
  532. #define ISupportErrorInfo_Value VARIANT_FALSE 
  533. #define ILockBytes_Value VARIANT_FALSE 
  534. #define ISequentialStream_Value VARIANT_FALSE 
  535. #define IStorage_Value VARIANT_FALSE 
  536. #define IStream_Value VARIANT_FALSE 
  537. #define IDENTIFIERCASE_Value 0 
  538. #define IMMOBILEROWS_Value VARIANT_FALSE 
  539. #define INDEX_AUTOUPDATE_Value VARIANT_FALSE 
  540. #define INDEX_CLUSTERED_Value VARIANT_FALSE 
  541. #define INDEX_FILLFACTOR_Value 0 
  542. #define INDEX_INITIALSIZE_Value 0 
  543. #define INDEX_NULLCOLLATION_Value 0 
  544. #define INDEX_NULLS_Value 0 
  545. #define INDEX_PRIMARYKEY_Value VARIANT_FALSE 
  546. #define INDEX_SORTBOOKMARKS_Value VARIANT_FALSE 
  547. #define INDEX_TEMPINDEX_Value VARIANT_FALSE 
  548. #define INDEX_TYPE_Value 0 
  549. #define INDEX_UNIQUE_Value VARIANT_FALSE 
  550. #define INIT_DATASOURCE_Value OLESTR("") 
  551. #define INIT_HWND_Value 0 
  552. #define INIT_IMPERSONATION_LEVEL_Value 0 
  553. #define INIT_LCID_Value 0 
  554. #define INIT_LOCATION_Value OLESTR("") 
  555. #define INIT_MODE_Value 0 
  556. #define INIT_PROMPT_Value VT_I2 
  557. #define INIT_PROTECTION_LEVEL_Value 0 
  558. #define INIT_PROVIDERSTRING_Value OLESTR("") 
  559. #define INIT_TIMEOUT_Value 0 
  560. #define LITERALBOOKMARKS_Value VARIANT_FALSE 
  561. #define LITERALIDENTITY_Value VARIANT_FALSE 
  562. #define MAXINDEXSIZE_Value 0 
  563. #define MAXOPENROWS_Value 0 
  564. #define MAXPENDINGROWS_Value 0 
  565. #define MAXROWS_Value 0 
  566. #define MAXROWSIZE_Value 0
  567. #define MAXROWSIZEINCLUDESBLOB_Value VARIANT_FALSE 
  568. #define MAXTABLESINSELECT_Value 0 
  569. #define MAYWRITECOLUMN_Value VARIANT_FALSE 
  570. #define MEMORYUSAGE_Value 0 
  571. #define MULTIPLEPARAMSETS_Value VARIANT_FALSE 
  572. #define MULTIPLERESULTS_Value 0 
  573. #define MULTIPLESTORAGEOBJECTS_Value VARIANT_FALSE  
  574. #define MULTITABLEUPDATE_Value VARIANT_FALSE 
  575. #define NOTIFICATIONPHASES_Value 0 
  576. #define NOTIFYCOLUMNSET_Value 0 
  577. #define NOTIFYROWDELETE_Value 0 
  578. #define NOTIFYROWFIRSTCHANGE_Value 0 
  579. #define NOTIFYROWINSERT_Value 0 
  580. #define NOTIFYROWRESYNCH_Value 0 
  581. #define NOTIFYROWSETRELEASE_Value 0 
  582. #define NOTIFYROWSETFETCHPOSITIONCHANGE_Value 0 
  583. #define NOTIFYROWUNDOCHANGE_Value 0 
  584. #define NOTIFYROWUNDODELETE_Value 0 
  585. #define NOTIFYROWUNDOINSERT_Value 0 
  586. #define NOTIFYROWUPDATE_Value 0 
  587. #define NULLCOLLATION_Value 0 
  588. #define OLEOBJECTS_Value 0
  589. #define ORDERBYCOLUMNSINSELECT_Value VARIANT_FALSE 
  590. #define ORDEREDBOOKMARKS_Value VARIANT_FALSE 
  591. #define OTHERINSERT_Value VARIANT_FALSE 
  592. #define OTHERUPDATEDELETE_Value VARIANT_FALSE
  593. #define OUTPUTPARAMETERAVAILABILITY_Value 0 
  594. #define OWNINSERT_Value VARIANT_FALSE 
  595. #define OWNUPDATEDELETE_Value VARIANT_FALSE 
  596. #define PERSISTENTIDTYPE_Value 0 
  597. #define PREPAREABORTBEHAVIOR_Value 0 
  598. #define PREPARECOMMITBEHAVIOR_Value 0 
  599. #define PROCEDURETERM_Value OLESTR("") 
  600. #define PROVIDERNAME_Value OLESTR("") 
  601. #define PROVIDEROLEDBVER_Value OLESTR("2.0") 
  602. #define PROVIDERVER_Value OLESTR("") 
  603. #define QUICKRESTART_Value VARIANT_FALSE 
  604. #define QUOTEDIDENTIFIERCASE_Value 0 
  605. #define REENTRANTEVENTS_Value VARIANT_FALSE 
  606. #define REMOVEDELETED_Value VARIANT_FALSE 
  607. #define REPORTMULTIPLECHANGES_Value VARIANT_FALSE 
  608. #define RETURNPENDINGINSERTS_Value VARIANT_FALSE 
  609. #define ROWRESTRICT_Value VARIANT_FALSE 
  610. #define ROWSETCONVERSIONSONCOMMAND_Value VARIANT_TRUE 
  611. #define ROWTHREADMODEL_Value 0 
  612. #define SCHEMATERM_Value OLESTR("") 
  613. #define SCHEMAUSAGE_Value 0 
  614. #define SERVERCURSOR_Value VARIANT_FALSE
  615. #define SESS_AUTOCOMMITISOLEVELS_Value 0 
  616. #define SQLSUPPORT_Value 0 
  617. #define STRONGIDENTITY_Value VARIANT_FALSE 
  618. #define STRUCTUREDSTORAGE_Value 0 
  619. #define SUBQUERIES_Value 0 
  620. #define SUPPORTEDTXNDDL_Value 0 
  621. #define SUPPORTEDTXNISOLEVELS_Value 0 
  622. #define SUPPORTEDTXNISORETAIN_Value 0 
  623. #define TABLETERM_Value OLESTR("") 
  624. #define TBL_TEMPTABLE_Value VARIANT_FALSE 
  625. #define TRANSACTEDOBJECT_Value VARIANT_FALSE 
  626. #define UPDATABILITY_Value 0 
  627. #define USERNAME_Value OLESTR("") 
  628.  
  629.  
  630. #define BEGIN_PROPSET_MAP(Class) \
  631. static UPROPSET* _GetPropSet(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet = NULL, GUID* pguidSet = (GUID*)&(GUID_NULL)) \
  632. { \
  633.     typedef Class _PropSetClass; \
  634.     ULONG& cElemsMax = *pcElemPerSupported; \
  635.     cElemsMax = 0; \
  636.     int nCurProp = 0; \
  637.     int cRemainder = 0;
  638.  
  639. #define BEGIN_PROPERTY_SET_EX(guid, flags) \
  640. if (pNumPropSets != NULL) \
  641. { \
  642.     pSet[nCurProp].pPropSet = &guid; \
  643.     pSet[nCurProp].dwFlags = flags; \
  644. } \
  645. static const UPROPINFO aProperty##guid[] = \
  646. {
  647.  
  648. #define BEGIN_PROPERTY_SET(guid) BEGIN_PROPERTY_SET_EX(guid, 0)
  649.  
  650. #define PROPERTY_INFO_ENTRY_EX(dwPropID, vt, dwFlags, value, options) DBPROP_##dwPropID, IDS_DBPROP_##dwPropID, vt, dwFlags, (DWORD)value, (DBPROPOPTIONS)options,
  651.  
  652. #define PROPERTY_INFO_ENTRY_VALUE(dwPropID, value) PROPERTY_INFO_ENTRY_EX(dwPropID, dwPropID##_Type, ##dwPropID##_Flags, value, 0)
  653.  
  654. #define PROPERTY_INFO_ENTRY(dwPropID) PROPERTY_INFO_ENTRY_VALUE(dwPropID, dwPropID##_Value)
  655.  
  656.  
  657. #define END_PROPERTY_SET(guid) \
  658.         }; \
  659.         if (pNumPropSets != NULL) \
  660.         { \
  661.             pSet[nCurProp].pUPropInfo = (UPROPINFO*)aProperty##guid; \
  662.             pSet[nCurProp].cUPropInfo = sizeof(aProperty##guid) / sizeof(UPROPINFO); \
  663.             cRemainder = (pSet[nCurProp].cUPropInfo % 32) ? 1 : 0; \
  664.             if (cElemsMax < (pSet[nCurProp].cUPropInfo / 32 + cRemainder)) \
  665.             { \
  666.                 cElemsMax = (pSet[nCurProp].cUPropInfo / 32 + cRemainder); \
  667.             } \
  668.         } \
  669.         nCurProp++;
  670.  
  671. #define CHAIN_PROPERTY_SET(ChainClass) \
  672.         ULONG cPropSets##ChainClass, cElsSupported##ChainClass; \
  673.         int cSets##ChainClass = (int)ChainClass::_GetPropSet(NULL, &cElsSupported##ChainClass); \
  674.         if (pNumPropSets != NULL) \
  675.         { \
  676.             UPROPSET* pSetA = (UPROPSET*)_alloca(sizeof(UPROPSET)*cSets##ChainClass); \
  677.             UPROPSET* pSetTemp = ChainClass::_GetPropSet(&cPropSets##ChainClass, &cElsSupported##ChainClass, pSetA); \
  678.             cElemsMax = (cElemsMax < cElsSupported##ChainClass) ? cElsSupported##ChainClass : cElemsMax; \
  679.             ATLASSERT(pSetTemp); \
  680.             for (ULONG iSet = nCurProp; iSet < nCurProp+cPropSets##ChainClass; iSet++) \
  681.             { \
  682.                 pSet[iSet].pPropSet = pSetTemp[iSet-nCurProp].pPropSet; \
  683.                 pSet[iSet].dwFlags = pSetTemp[iSet-nCurProp].dwFlags; \
  684.                 pSet[iSet].pUPropInfo = pSetTemp[iSet-nCurProp].pUPropInfo; \
  685.                 pSet[iSet].cUPropInfo = pSetTemp[iSet-nCurProp].cUPropInfo; \
  686.             } \
  687.         } \
  688.         nCurProp += cSets##ChainClass;
  689.  
  690. #define END_PROPSET_MAP() \
  691.     if (pNumPropSets != NULL) \
  692.     { \
  693.         if (IsEqualGUID(*pguidSet, GUID_NULL)) \
  694.         { \
  695.             *pNumPropSets = nCurProp; \
  696.             return pSet; \
  697.         } \
  698.         else \
  699.         { \
  700.             *pNumPropSets = 1; \
  701.             UINT i = 0; \
  702.             for (; i < sizeof(pSet)/sizeof(UPROPSET) && IsEqualGUID(*(pSet[i].pPropSet), *pguidSet); i++); \
  703.             return (i == sizeof(pSet)/sizeof(UPROPSET)) ? &pSet[0] : &pSet[i]; \
  704.         } \
  705.     } \
  706.     return (UPROPSET*)nCurProp; \
  707.     }
  708.  
  709.  
  710. // For DataSource flags IDBInitialize::m_dwStatus
  711. enum DATASOURCE_FLAGS {
  712.     DSF_MASK_INIT            = 0xFFFFF00F,    // Mask for stuff lasting over init/uninit.
  713.     DSF_PERSIST_DIRTY        = 0x00000001,    // Set if init string changes.
  714.     DSF_INITIALIZED            = 0x00000010,    // Have we been initialized.
  715. };
  716.  
  717.  
  718. #define DBID_USE_GUID_OR_PGUID(e) \
  719.     ((1<<(e)) & \
  720.     ( 1<<DBKIND_GUID \
  721.     | 1<<DBKIND_GUID_NAME \
  722.     | 1<<DBKIND_GUID_PROPID \
  723.     | 1<<DBKIND_PGUID_NAME \
  724.     | 1<<DBKIND_PGUID_PROPID ))
  725.  
  726. #define DBID_USE_GUID(e) \
  727.     ((1<<(e)) & \
  728.     ( 1<<DBKIND_GUID \
  729.     | 1<<DBKIND_GUID_NAME \
  730.     | 1<<DBKIND_GUID_PROPID ))
  731.  
  732. #define DBID_USE_PGUID(e) \
  733.     ((1<<(e)) & \
  734.     ( 1<<DBKIND_PGUID_NAME \
  735.     | 1<<DBKIND_PGUID_PROPID ))
  736.  
  737. #define DBID_USE_NAME(e) \
  738.     ((1<<(e)) & \
  739.     ( 1<<DBKIND_NAME \
  740.     | 1<<DBKIND_GUID_NAME \
  741.     | 1<<DBKIND_PGUID_NAME ))
  742.  
  743. #define DBID_USE_PROPID(e) \
  744.     ((1<<(e)) & \
  745.     ( 1<<DBKIND_PROPID \
  746.     | 1<<DBKIND_GUID_PROPID \
  747.     | 1<<DBKIND_PGUID_PROPID ))
  748.  
  749. // Bookmark can be either guid or pguid.
  750. #define DBID_IS_BOOKMARK(dbid) \
  751.     (  DBID_USE_GUID(dbid.eKind)  &&  dbid.uGuid.guid  == DBCOL_SPECIALCOL \
  752.     || DBID_USE_PGUID(dbid.eKind) && *dbid.uGuid.pguid == DBCOL_SPECIALCOL )
  753.  
  754. #define DivDword(dw) (dw >> 5)        // dw / 32 = dw / (sizeof(DWORD)*8)
  755. #define ModDword(dw) (dw & (32-1))    // dw % 32
  756. #define DwordSizeofBits(nBits) (nBits/32+1)    // Use in array declarations
  757. #define CLEARBITARRAY( rgdwFlags ) memset( rgdwFlags, 0, sizeof(rgdwFlags) )
  758.  
  759. template <class T>
  760. BOOL InRange(T& val, T& valMin, T& valMax)
  761. {
  762.     return ( valMin <= val && val <= valMax );
  763. }
  764. // Implementation Class 
  765. class CBitFieldOps
  766. {
  767. public:
  768.     void SETBIT( DWORD rgdwFlags[], const DWORD dwBit )
  769.     {
  770.         rgdwFlags[DivDword(dwBit)] |= 1 << ModDword(dwBit);
  771.     }
  772.  
  773.     void CLEARBIT( DWORD rgdwFlags[], const DWORD dwBit )
  774.     {
  775.         rgdwFlags[DivDword(dwBit)] &= ~( 1 << ModDword(dwBit) );
  776.     }
  777.  
  778.     DWORD TESTBIT( const DWORD rgdwFlags[], const DWORD dwBit )
  779.     {
  780.         //old//Note: Not {0,1}, but from {0...2^32-1}.
  781.         // Note: Now returns {0,1}.
  782.         return ( rgdwFlags[DivDword(dwBit)] & ( 1 << ModDword(dwBit) ) ) != 0;
  783.     }
  784. };
  785.  
  786. // Implementation Class 
  787. class CDBIDOps
  788. {
  789. public:
  790.     HRESULT CompareDBIDs(const DBID* pdbid1, const DBID* pdbid2)
  791.     {
  792.         // Array of valid eKind matches, in addition to matching exactly.
  793.         static BYTE s_rgbKind[] =
  794.         {
  795.             DBKIND_PGUID_NAME,        // DBKIND_GUID_NAME
  796.             DBKIND_PGUID_PROPID,    // DBKIND_GUID_PROPID
  797.             DBKIND_NAME,            // DBKIND_NAME
  798.             DBKIND_GUID_NAME,        // DBKIND_PGUID_NAME
  799.             DBKIND_GUID_PROPID,        // DBKIND_PGUID_PROPID
  800.             DBKIND_PROPID,            // DBKIND_PROPID
  801.             DBKIND_GUID                // DBKIND_GUID
  802.         };
  803.  
  804.         if( !pdbid1 || !pdbid2 )
  805.             return S_FALSE;
  806.  
  807.         // Assume a match, and discard early if we can.
  808.         if (!InRange(pdbid2->eKind, (DWORD)0, (DWORD)(sizeof(s_rgbKind)/sizeof(*s_rgbKind))))
  809.         {
  810.             ATLTRACE2(atlTraceDBProvider, 0, "Column ID out of Range\n");
  811.             return E_FAIL;
  812.         }
  813.         if (pdbid1->eKind != pdbid2->eKind
  814.         &&  pdbid1->eKind != s_rgbKind[pdbid2->eKind])
  815.             return S_FALSE;
  816.  
  817.         if (DBID_USE_GUID_OR_PGUID(pdbid1->eKind))
  818.         {
  819.             if (!DBID_USE_GUID_OR_PGUID(pdbid2->eKind))
  820.                 return S_FALSE;
  821.             // Compare GUIDs.
  822.             // Note that _GUID_ is equivalent to _PGUID_.
  823.             if (!InlineIsEqualGUID(
  824.                     DBID_USE_PGUID(pdbid1->eKind) ? *(pdbid1->uGuid.pguid) : pdbid1->uGuid.guid,
  825.                     DBID_USE_PGUID(pdbid2->eKind) ? *(pdbid2->uGuid.pguid) : pdbid2->uGuid.guid ))
  826.                 return S_FALSE;
  827.         }
  828.         if (DBID_USE_NAME(pdbid1->eKind))
  829.         {
  830.             if (!DBID_USE_NAME(pdbid2->eKind))
  831.                 return S_FALSE;
  832.             // Compare names.
  833.             // Need to check if 1 is null and the other is not.
  834.             if ( ((pdbid1->uName.pwszName == NULL) &&
  835.                   (pdbid2->uName.pwszName != NULL)) || 
  836.                  ((pdbid1->uName.pwszName != NULL) &&
  837.                   (pdbid2->uName.pwszName == NULL)) )
  838.                  return S_FALSE;
  839.             // Since the above check does not rule out both being null, which is
  840.             // a valid comparison, and wcscmp will GPF if they were, we need
  841.             // to check for valid pointers
  842.             if( pdbid1->uName.pwszName && pdbid2->uName.pwszName )
  843.             {
  844.                 // Assume null-terminated.
  845.                 // Assume LCID match is OK (note diff with lstrcmp(), CompareString().)
  846.                 if (wcscmp(pdbid1->uName.pwszName, pdbid2->uName.pwszName) != 0)
  847.                     return S_FALSE;
  848.             }
  849.         }
  850.         if (DBID_USE_PROPID(pdbid1->eKind))
  851.         {
  852.             if (!DBID_USE_PROPID(pdbid2->eKind))
  853.                 return S_FALSE;
  854.             // Compare PROPID.
  855.             if (pdbid1->uName.ulPropid != pdbid2->uName.ulPropid)
  856.                 return S_FALSE;
  857.         }
  858.  
  859.         // No reason to discard, so must have matched each field successfully.
  860.         return S_OK;
  861.     }
  862.  
  863.     static HRESULT IsValidDBID(const DBID*    pdbid1)
  864.     {
  865.         ATLASSERT( pdbid1 );
  866.  
  867.         if( pdbid1 &&
  868.             ((pdbid1->eKind == DBKIND_GUID_NAME) ||
  869.             (pdbid1->eKind == DBKIND_GUID_PROPID) ||
  870.             (pdbid1->eKind == DBKIND_NAME) ||
  871.             (pdbid1->eKind == DBKIND_PGUID_NAME) ||
  872.             (pdbid1->eKind == DBKIND_PGUID_PROPID) ||
  873.             (pdbid1->eKind == DBKIND_PROPID) ||
  874.             (pdbid1->eKind == DBKIND_GUID)) )
  875.             return S_OK;
  876.         else
  877.             return S_FALSE;
  878.     }
  879.     HRESULT CopyDBIDs(DBID*    pdbidDest,    const DBID*    pdbidSrc)
  880.     {
  881.         size_t    cwchBuffer;
  882.  
  883.         ATLASSERT( pdbidDest || pdbidSrc );
  884.  
  885.         if( !pdbidDest || !pdbidSrc )
  886.             return S_FALSE;
  887.  
  888.         // Save eKind
  889.         pdbidDest->eKind = pdbidSrc->eKind;
  890.  
  891.         switch( pdbidSrc->eKind )
  892.         {
  893.  
  894.             case DBKIND_GUID_NAME:
  895.                 pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid;
  896.                 cwchBuffer = ocslen(pdbidSrc->uName.pwszName);
  897.                 cwchBuffer++;
  898.                 pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR));
  899.                 if( pdbidDest->uName.pwszName ) 
  900.                     memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR));
  901.                 else
  902.                     return E_OUTOFMEMORY;
  903.                 break;
  904.  
  905.             case DBKIND_GUID_PROPID:
  906.                 pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid;
  907.                 pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid;
  908.                 break;
  909.             case DBKIND_NAME:
  910.                 cwchBuffer = ocslen(pdbidSrc->uName.pwszName);
  911.                 cwchBuffer++;
  912.                 pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR));
  913.                 if( pdbidDest->uName.pwszName ) 
  914.                     memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR));
  915.                 else
  916.                     return E_OUTOFMEMORY;
  917.                 break;
  918.             case DBKIND_PGUID_NAME:
  919.                 pdbidDest->uGuid.pguid = (GUID*)CoTaskMemAlloc(sizeof(GUID));
  920.                 if( pdbidDest->uGuid.pguid )
  921.                 {
  922.                     *(pdbidDest->uGuid.pguid) = *(pdbidSrc->uGuid.pguid); 
  923.                     cwchBuffer = ocslen(pdbidSrc->uName.pwszName);
  924.                     cwchBuffer++;
  925.                     pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR));
  926.                     if( pdbidDest->uName.pwszName ) 
  927.                     {
  928.                         memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR));
  929.                         break;
  930.                     }
  931.                     else
  932.                     {
  933.                         CoTaskMemFree(pdbidDest->uGuid.pguid); 
  934.                         pdbidDest->uGuid.pguid = NULL;
  935.                     }
  936.                 }
  937.                 return E_OUTOFMEMORY;
  938.             case DBKIND_PGUID_PROPID:
  939.                 pdbidDest->uGuid.pguid = (GUID*)CoTaskMemAlloc(sizeof(GUID));
  940.                 if( pdbidDest->uGuid.pguid )
  941.                     *(pdbidDest->uGuid.pguid) = *(pdbidSrc->uGuid.pguid); 
  942.                 else
  943.                     return E_OUTOFMEMORY;
  944.                 pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid;
  945.                 break;
  946.             case DBKIND_PROPID:
  947.                 pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid;
  948.                 break;
  949.             case DBKIND_GUID:
  950.                 pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid;
  951.                 break;
  952.             default:
  953.                 ATLASSERT(L"Unhandled dbid1.ekind");
  954.                 return S_FALSE;
  955.         }
  956.  
  957.         return S_OK;
  958.     }
  959.     static GUID* GetDBIDpGuid(DBID& dbid)
  960.     {
  961.         GUID* pGuid;
  962.         switch (dbid.eKind)
  963.         {
  964.         case DBKIND_PGUID_NAME:
  965.         case DBKIND_PGUID_PROPID:
  966.             pGuid = dbid.uGuid.pguid;
  967.             break;
  968.         case DBKIND_GUID_NAME:
  969.         case DBKIND_GUID_PROPID:
  970.         case DBKIND_GUID:
  971.             pGuid = &(dbid.uGuid.guid);
  972.             break;
  973.         default:
  974.             pGuid = NULL;
  975.         }
  976.  
  977.         return pGuid;
  978.     }
  979.     static ULONG GetPropIDFromDBID(DBID& dbid)
  980.     {
  981.         switch (dbid.eKind)
  982.         {
  983.         case DBKIND_GUID_PROPID:
  984.         case DBKIND_PGUID_PROPID:
  985.         case DBKIND_PROPID:
  986.             return dbid.uName.ulPropid;
  987.         default:
  988.             return 0;
  989.         }
  990.     }
  991.     void FreeDBIDs(DBID* pdbidSrc)
  992.     {
  993.         switch( pdbidSrc->eKind )
  994.         {
  995.  
  996.             case DBKIND_GUID_NAME:
  997.                 CoTaskMemFree(pdbidSrc->uName.pwszName); 
  998.                 break;
  999.             case DBKIND_NAME:
  1000.                 CoTaskMemFree(pdbidSrc->uName.pwszName); 
  1001.                 break;
  1002.             case DBKIND_PGUID_NAME:
  1003.                 CoTaskMemFree(pdbidSrc->uGuid.pguid); 
  1004.                 CoTaskMemFree(pdbidSrc->uName.pwszName); 
  1005.                 break;
  1006.             case DBKIND_PGUID_PROPID:
  1007.                 CoTaskMemFree(pdbidSrc->uGuid.pguid); 
  1008.                 break;
  1009.             case DBKIND_GUID_PROPID:
  1010.             case DBKIND_PROPID:
  1011.             case DBKIND_GUID:
  1012.                 break;
  1013.             default:
  1014.                 ATLASSERT(L"Unhandled dbid1.ekind");
  1015.                 break;
  1016.         }
  1017.     }
  1018. };
  1019.  
  1020. extern "C" const CLSID CLSID_DataConvert;
  1021.  
  1022. class CConvertHelper
  1023. {
  1024. public:
  1025.     CConvertHelper() {}
  1026.     HRESULT FinalConstruct()
  1027.     {
  1028.         return ::CoCreateInstance(CLSID_DataConvert, NULL, CLSCTX_INPROC_SERVER, IID_IDataConvert, (void**)&m_spConvert);
  1029.     }
  1030.     CComPtr<IDataConvert> m_spConvert;
  1031. };
  1032.  
  1033. // IDBCreateSessionImpl
  1034. template <class T, class SessionClass>
  1035. class ATL_NO_VTABLE IDBCreateSessionImpl : public IDBCreateSession
  1036. {
  1037. public:
  1038.     STDMETHOD(CreateSession)(IUnknown *pUnkOuter,
  1039.                              REFIID riid,
  1040.                              IUnknown **ppDBSession)
  1041.     {
  1042.         ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateSessionImpl::CreateSession\n");
  1043.         if (ppDBSession == NULL)
  1044.             return E_INVALIDARG;
  1045.         T* pT = (T*)this;
  1046.         if (!(pT->m_dwStatus & DSF_INITIALIZED))
  1047.         {
  1048.             ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateSessionImpl::CreateSession : Error not initialized\n");
  1049.             *ppDBSession = NULL;
  1050.             return E_UNEXPECTED;
  1051.         }
  1052.         CComPolyObject<SessionClass> *pSession;
  1053.  
  1054.         // You can't QI for an interface other than IUnknown when aggregating 
  1055.         // and creating the object.  You might ask for your own interface, 
  1056.         // which would be bad.  Note, we return DB_E_NOAGGREGATION instead of
  1057.         // CLASS_E_NOAGGREGATION due to OLE DB constraints.
  1058.         if (pUnkOuter != NULL && !InlineIsEqualUnknown(riid))
  1059.             return DB_E_NOAGGREGATION;
  1060.  
  1061.         HRESULT hr = CComPolyObject<SessionClass>::CreateInstance(pUnkOuter, &pSession);
  1062.         if (SUCCEEDED(hr))
  1063.         {
  1064.             CComPtr<IObjectWithSite> spCreator;
  1065.             hr = pSession->m_contained.QueryInterface(IID_IObjectWithSite, (void**)&spCreator);
  1066.             if (SUCCEEDED(hr))
  1067.             {
  1068.                 spCreator->SetSite(this);
  1069.                 hr = pSession->QueryInterface(riid, (void**)ppDBSession);
  1070.             }
  1071.             else
  1072.                 delete pSession;
  1073.         }
  1074.         return hr;
  1075.     }
  1076. };
  1077.  
  1078. // IDBInitializeImpl
  1079. template <class T>
  1080. class ATL_NO_VTABLE IDBInitializeImpl : public IDBInitialize
  1081. {
  1082. public:
  1083.     IDBInitializeImpl()
  1084.     {
  1085.         m_dwStatus = 0; 
  1086.         m_pCUtlPropInfo = NULL;
  1087.         m_cSessionsOpen = 0;
  1088.     }
  1089.     ~IDBInitializeImpl()
  1090.     {
  1091.         delete m_pCUtlPropInfo;
  1092.     }
  1093.  
  1094.     STDMETHOD(Uninitialize)(void)
  1095.     {
  1096.         ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Uninitialize\n");
  1097.         T* pT = (T*)this;
  1098.         pT->Lock();
  1099.         if (pT->m_cSessionsOpen != 0)
  1100.         {
  1101.             ATLTRACE2(atlTraceDBProvider, 0, "Uninitialized called with Open Sessions\n");
  1102.             return DB_E_OBJECTOPEN;
  1103.         }
  1104.         delete m_pCUtlPropInfo;
  1105.         m_pCUtlPropInfo = NULL;
  1106.         pT->m_dwStatus |= DSF_PERSIST_DIRTY;
  1107.         pT->m_dwStatus &= DSF_MASK_INIT;    // Clear all non-init flags.
  1108.         pT->Unlock();
  1109.         return S_OK;
  1110.  
  1111.     }
  1112.  
  1113.     LONG m_cSessionsOpen;
  1114.     DWORD m_dwStatus;
  1115.     CUtlPropInfo<T>* m_pCUtlPropInfo;
  1116.  
  1117.     STDMETHOD(Initialize)(void)
  1118.     {
  1119.  
  1120.         ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize\n");
  1121.         T *pT = (T*)(this);
  1122.         T::ObjectLock lock(pT);
  1123.         HRESULT hr;
  1124.         if (pT->m_dwStatus & DSF_INITIALIZED)
  1125.         {
  1126.             ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize Error : Already Initialized\n");
  1127.             return DB_E_ALREADYINITIALIZED;
  1128.         }
  1129.         delete m_pCUtlPropInfo;
  1130.         m_pCUtlPropInfo = NULL;
  1131.         ATLTRY(m_pCUtlPropInfo = new CUtlPropInfo<T>())
  1132.         if (m_pCUtlPropInfo == NULL)
  1133.         {
  1134.             ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize Error : OOM\n");
  1135.             return E_OUTOFMEMORY;
  1136.         }
  1137.         hr = m_pCUtlPropInfo->FInit();
  1138.         if (hr == S_OK)
  1139.         {
  1140.             pT->m_dwStatus |= DSF_INITIALIZED;
  1141.         }
  1142.         else
  1143.         {
  1144.             delete m_pCUtlPropInfo;
  1145.             m_pCUtlPropInfo = NULL;
  1146.         }
  1147.         return hr;
  1148.     }
  1149.  
  1150. };
  1151.  
  1152.  
  1153. // Implementation Class 
  1154.  
  1155. class CPropColID : 
  1156.     public PROPCOLID,
  1157.     public CDBIDOps
  1158. {
  1159. public:
  1160.     CPropColID()
  1161.     {
  1162.         VariantInit(&vValue);
  1163.     }
  1164.     ~CPropColID()
  1165.     {
  1166.         FreeDBIDs(&dbidProperty);
  1167.         VariantClear(&vValue);
  1168.     }
  1169.     bool operator==(const CPropColID& colId)
  1170.     {
  1171.         return (CompareDBIDs(&dbidProperty, &(colId.dbidProperty)) == S_OK) ? true : false;
  1172.     }
  1173.  
  1174. };
  1175.  
  1176. class CColumnIds : 
  1177.     public CDBIDOps,
  1178.     public CSimpleArray<CPropColID>
  1179.  
  1180. {
  1181. public:
  1182.     PPROPCOLID AddNode()
  1183.     {
  1184.         CPropColID colID;
  1185.         if (Add(colID))
  1186.             return &(m_aT[GetSize()]);
  1187.         return NULL;
  1188.     }
  1189.     HRESULT    RemoveColumnId(const DBID* pdbidProp)
  1190.     {
  1191.         for (int i = 0; i < GetSize(); i++)
  1192.         {
  1193.             if (CompareDBIDs(pdbidProp, &(m_aT[i].dbidProperty)) == S_OK)
  1194.                 return (RemoveAt(i)) ? S_OK : E_FAIL;
  1195.         }
  1196.  
  1197.         return E_FAIL;
  1198.     }
  1199.     HRESULT    AddColumnId(DBPROP* pProp)
  1200.     {
  1201.         CPropColID colID;
  1202.         HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pProp->colid));
  1203.         if(FAILED(hr))
  1204.             return hr;
  1205.         colID.dwOption = pProp->dwOptions;
  1206.         hr = VariantCopy(&(colID.vValue),&(pProp->vValue));
  1207.         if(FAILED(hr))
  1208.             return hr;
  1209.         return (Add(colID)) ? S_OK : E_OUTOFMEMORY;
  1210.  
  1211.     }
  1212.     HRESULT    AddColumnId(PPROPCOLID pPropNode)
  1213.     {
  1214.         CPropColID colID;
  1215.         HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pPropNode->dbidProperty));
  1216.         if(FAILED(hr))
  1217.             return hr;
  1218.         colID.dwOption = pPropNode->dwOption;
  1219.         hr = VariantCopy(&(colID.vValue),&(pPropNode->vValue));
  1220.         if(FAILED(hr))
  1221.             return hr;
  1222.         return (Add(colID)) ? S_OK : E_OUTOFMEMORY;
  1223.  
  1224.     }
  1225.     ULONG GetCountOfPropColids(){ return (ULONG)GetSize();}
  1226.     PPROPCOLID FindColumnId(const DBID* pdbidProp)
  1227.     {
  1228.         for (int i = 0; i < GetSize(); i++)
  1229.         {
  1230.             if (CompareDBIDs(pdbidProp, &(m_aT[i].dbidProperty)) == S_OK)
  1231.                 return &(m_aT[i]);
  1232.         }
  1233.  
  1234.         return NULL;
  1235.     }
  1236.     HRESULT GetValue(int iColId, DWORD* pdwOptions, DBID* pColid, VARIANT* pvValue)
  1237.     {
  1238.         HRESULT        hr;
  1239.  
  1240.         ATLASSERT(pdwOptions && pColid && pvValue);
  1241.         ATLASSERT(iColId >= 0 && iColId < m_nSize);
  1242.  
  1243.         CPropColID& colId = m_aT[iColId];
  1244.         *pdwOptions = colId.dwOption;
  1245.         CopyDBIDs( pColid, &(colId.dbidProperty) );
  1246.         if(FAILED(hr = VariantCopy(pvValue, &(colId.vValue))))
  1247.             return hr;
  1248.         return S_OK;
  1249.     }
  1250. };
  1251.  
  1252. const ULONG        cchDescBuffSize = 256;
  1253. const DWORD        DBINTERNFLAGS_CHANGED        = 0x00000001;
  1254. // Rules for GetPropertiesArgChk
  1255. const DWORD        ARGCHK_PROPERTIESINERROR    = 0x00000001;
  1256.  
  1257. // Implementation Class 
  1258. template <class T>
  1259. class CUtlPropInfo : public CBitFieldOps, public CDBIDOps
  1260. {
  1261. public:
  1262.     enum EnumGetPropInfo
  1263.     {
  1264.         GETPROPINFO_ALLPROPIDS        = 0x0001,
  1265.         GETPROPINFO_NOTSUPPORTED    = 0x0002,
  1266.         GETPROPINFO_ERRORSOCCURRED    = 0x0004,
  1267.         GETPROPINFO_VALIDPROP        = 0x0008
  1268.     };
  1269.  
  1270.     CUtlPropInfo()
  1271.     {
  1272.         m_cUPropSet         = 0;
  1273.         m_pUPropSet         = NULL;
  1274.         m_pUPropSetToDel = NULL;
  1275.  
  1276.         m_cPropSetDex    = 0;
  1277.         m_rgiPropSetDex    = NULL;
  1278.  
  1279.         m_cElemPerSupported = 0;
  1280.         m_rgdwSupported = NULL;
  1281.     }
  1282.     ~CUtlPropInfo()
  1283.     {
  1284.         delete[] m_rgiPropSetDex;
  1285.         delete[] m_rgdwSupported;
  1286.         if (m_pUPropSetToDel != NULL)
  1287.             CoTaskMemFree(m_pUPropSetToDel);
  1288.     }
  1289.  
  1290.     //Determine the number of description buffers needed
  1291.     ULONG CalcDescripBuffers(ULONG cPropInfoSet, DBPROPINFOSET* pPropInfoSet)
  1292.     {
  1293.         ULONG    cBuffers = 0;
  1294.  
  1295.         ATLASSERT(m_pUPropSet);
  1296.         ATLASSERT(cPropInfoSet && pPropInfoSet);
  1297.  
  1298.         for(ULONG ulSet=0; ulSet<cPropInfoSet; ulSet++)
  1299.         {
  1300.             if( GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_OK)
  1301.             {
  1302.                 for(ULONG ul=0; ul<m_cPropSetDex; ul++)
  1303.                 {
  1304.                     cBuffers += m_pUPropSet[m_rgiPropSetDex[ul]].cUPropInfo;
  1305.                 }
  1306.             }
  1307.         }
  1308.  
  1309.         return cBuffers;
  1310.     }
  1311.     //Retrieve the property set indexes that match this property set.
  1312.     HRESULT    GetPropertySetIndex(const GUID* pPropertySet)
  1313.     {
  1314.         DWORD    dwFlag = 0;
  1315.         ULONG    ulSet;
  1316.  
  1317.         ATLASSERT(m_cUPropSet && m_pUPropSet);
  1318.         ATLASSERT(m_rgiPropSetDex);
  1319.         ATLASSERT(pPropertySet);
  1320.  
  1321.         m_cPropSetDex = 0;
  1322.  
  1323.         if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_DATASOURCEALL))
  1324.         {
  1325.             dwFlag = DBPROPFLAGS_DATASOURCE;
  1326.         }
  1327.         else if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_DATASOURCEINFOALL))
  1328.         {
  1329.             dwFlag = DBPROPFLAGS_DATASOURCEINFO;
  1330.         }
  1331.         else if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_ROWSETALL))
  1332.         {
  1333.             dwFlag = DBPROPFLAGS_ROWSET;
  1334.         }
  1335.         else if(InlineIsEqualGUID(*pPropertySet,DBPROPSET_DBINITALL))
  1336.         {
  1337.             dwFlag = DBPROPFLAGS_DBINIT;
  1338.         }
  1339.         else if(InlineIsEqualGUID(*pPropertySet,DBPROPSET_SESSIONALL))
  1340.         {
  1341.             dwFlag = DBPROPFLAGS_SESSION;
  1342.         }
  1343.         else // No scan required, just look for match.
  1344.         {
  1345.             for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  1346.             {
  1347.                 if( *(m_pUPropSet[ulSet].pPropSet) == *pPropertySet )
  1348.                 {
  1349.                     m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  1350.                     m_cPropSetDex++;
  1351.                     break;
  1352.                 }
  1353.             }
  1354.             goto EXIT;
  1355.         }
  1356.  
  1357.         // Scan through the property sets looking for matching attributes
  1358.         for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  1359.         {
  1360.             if( m_pUPropSet[ulSet].pUPropInfo[0].dwFlags & dwFlag )
  1361.             {
  1362.                 m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  1363.                 m_cPropSetDex++;
  1364.             }
  1365.         }
  1366.  
  1367.     EXIT:
  1368.         return (m_cPropSetDex) ? S_OK : S_FALSE;
  1369.  
  1370.     }
  1371.     //Retrieve the property id pointer 
  1372.     HRESULT    GetUPropInfoPtr(ULONG iPropSetDex, DBPROPID dwPropertyId, UPROPINFO** ppUPropInfo)
  1373.     {
  1374.         // Scan through the property sets looking for matching attributes
  1375.         for(ULONG ulProps=0; ulProps<m_pUPropSet[iPropSetDex].cUPropInfo; ulProps++)
  1376.         {
  1377.             if( m_pUPropSet[iPropSetDex].pUPropInfo[ulProps].dwPropId == dwPropertyId )
  1378.             {
  1379.                 *ppUPropInfo = &(m_pUPropSet[iPropSetDex].pUPropInfo[ulProps]);
  1380.                 // Test to see if the property is supported for this
  1381.                 // instantiation
  1382.                 return (TESTBIT(&(m_rgdwSupported[iPropSetDex * m_cElemPerSupported]), ulProps)) ? S_OK : S_FALSE;
  1383.             }
  1384.         }
  1385.         return S_FALSE;
  1386.     }
  1387.     HRESULT    FInit(GUID* pguidSet = (GUID*)&GUID_NULL)
  1388.     {
  1389.         HRESULT hr;
  1390.  
  1391.         InitAvailUPropSets(&m_cUPropSet, &m_pUPropSet, &m_cElemPerSupported, pguidSet);
  1392.         ATLASSERT((m_cUPropSet != 0) && (m_cElemPerSupported != 0));
  1393.         if(!m_cUPropSet || !m_cElemPerSupported)
  1394.             return E_FAIL;
  1395.  
  1396.         ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
  1397.         if(m_rgdwSupported == NULL)
  1398.             return E_OUTOFMEMORY;
  1399.  
  1400.         if(FAILED(hr = InitUPropSetsSupported()))
  1401.         {
  1402.             delete[] m_rgdwSupported;
  1403.             m_rgdwSupported = NULL;
  1404.             return hr;
  1405.         }
  1406.         if(m_cUPropSet)
  1407.         {
  1408.             ATLTRY(m_rgiPropSetDex = new ULONG[m_cUPropSet])
  1409.             if(m_rgiPropSetDex == NULL)
  1410.             {
  1411.                 delete [] m_rgdwSupported;
  1412.                 return E_OUTOFMEMORY;
  1413.             }
  1414.         }
  1415.         return S_OK;
  1416.     }
  1417.     HRESULT    GetPropertyInfo(ULONG cPropertySets, 
  1418.                         const DBPROPIDSET rgPropertySets[], ULONG* pcPropertyInfoSets,
  1419.                         DBPROPINFOSET**    prgPropertyInfoSets, 
  1420.                         WCHAR** ppDescBuffer, bool bInitialized = true, 
  1421.                         const GUID* pGuid = NULL)
  1422.     {
  1423.         HRESULT    hr = S_OK;
  1424.         ULONG ul, ulSet, ulNext, ulEnd;
  1425.         ULONG ulOutIndex;
  1426.         ULONG cSets;
  1427.         ULONG cPropInfos;
  1428.         ULONG ulIndex = 0;
  1429.         DWORD dwStatus = 0;
  1430.         DBPROPINFO*    pPropInfo = NULL;
  1431.         DBPROPINFO*    pCurPropInfo = NULL;
  1432.         WCHAR* pDescBuffer = NULL;
  1433.         DBPROPINFOSET* pPropInfoSet = NULL;
  1434.         UPROPINFO* pUPropInfo = NULL;
  1435.         WCHAR wszBuff[256];
  1436.         int    cch;
  1437.  
  1438.         // If the consumer does not restrict the property sets
  1439.         // by specify an array of property sets and a cPropertySets
  1440.         // greater than 0, then we need to make sure we 
  1441.         // have some to return
  1442.         if(cPropertySets == 0)
  1443.         {
  1444.             // Determine the number of property sets supported
  1445.             // In this case, it usually the enumerator or data source asking for 
  1446.             // DBPROPSET_DBINIT information.
  1447.  
  1448.             if (pGuid != NULL)
  1449.                 cSets = 1;        
  1450.             else
  1451.                 cSets = m_cUPropSet;
  1452.         }
  1453.         else
  1454.         {
  1455.             cSets = 0;
  1456.  
  1457.             // Determine number of property sets required 
  1458.             // This is only required when any of the "special" property set GUIDs were specified
  1459.             for(ulSet=0; ulSet<cPropertySets; ulSet++)
  1460.             {
  1461.                 if (GetPropertySetIndex(&(rgPropertySets[ulSet].guidPropertySet)) == S_OK)
  1462.                     cSets += m_cPropSetDex;
  1463.                 else
  1464.                     cSets++;
  1465.             }
  1466.         }
  1467.         ATLASSERT(cSets);
  1468.  
  1469.         // Allocate the DBPROPINFOSET structures
  1470.         pPropInfoSet = (DBPROPINFOSET*)CoTaskMemAlloc(cSets * sizeof(DBPROPINFOSET));
  1471.         if(pPropInfoSet == NULL)
  1472.         {
  1473.             ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROPSET array for GetProperties\n");
  1474.             hr =  E_OUTOFMEMORY;
  1475.             goto EXIT;
  1476.         }
  1477.  
  1478.         memset(pPropInfoSet, 0, cSets * sizeof(DBPROPINFOSET));
  1479.  
  1480.         ulOutIndex = 0;
  1481.         ulEnd = cPropertySets == 0 ? cSets : cPropertySets; 
  1482.         // Fill in the output array
  1483.         for(ulSet=0; ulSet<ulEnd; ulSet++)
  1484.         {
  1485.              // Depending of if Property sets are specified store the
  1486.             // return property set.
  1487.             if (cPropertySets == 0)
  1488.             {
  1489.                 if (pGuid != NULL)
  1490.                 {
  1491.                     for (ULONG l=0; l<m_cUPropSet; l++)
  1492.                     {
  1493.                         if (InlineIsEqualGUID(*m_pUPropSet[l].pPropSet, *pGuid))
  1494.                             ulIndex = l;
  1495.                     }
  1496.  
  1497.                     if (l == m_cUPropSet)
  1498.                     {
  1499.                         ATLTRACE2(atlTraceDBProvider, 0, "Property Info Set not supported");
  1500.                         ulIndex = 0;
  1501.                     }
  1502.                     pPropInfoSet[ulSet].guidPropertySet = *pGuid;
  1503.                 }
  1504.                 else
  1505.                 {
  1506.                     pPropInfoSet[ulSet].guidPropertySet = *(m_pUPropSet[ulSet].pPropSet);
  1507.                 }
  1508.             }
  1509.             else
  1510.             {
  1511.                 GUID const& guidSet = rgPropertySets[ulSet].guidPropertySet;
  1512.                 if( (InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEALL) ||
  1513.                     InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEINFOALL) ||
  1514.                     InlineIsEqualGUID(guidSet, DBPROPSET_DBINITALL) ||
  1515.                     InlineIsEqualGUID(guidSet, DBPROPSET_SESSIONALL) ||
  1516.                     InlineIsEqualGUID(guidSet, DBPROPSET_ROWSETALL)) &&
  1517.                     GetPropertySetIndex(&guidSet) == S_OK )
  1518.                 {
  1519.                     for(ul=0; ul<m_cPropSetDex; ul++,ulOutIndex++)
  1520.                     {
  1521.                         pPropInfoSet[ulOutIndex].guidPropertySet    = *(m_pUPropSet[m_rgiPropSetDex[ul]].pPropSet);
  1522.                         pPropInfoSet[ulOutIndex].cPropertyInfos        = 0;
  1523.                     }
  1524.                 }
  1525.                 else
  1526.                 {
  1527.                     // Handle non-category property sets
  1528.                     // Handle unknown property sets
  1529.                     pPropInfoSet[ulOutIndex].guidPropertySet = guidSet; 
  1530.                     pPropInfoSet[ulOutIndex].cPropertyInfos     = rgPropertySets[ulSet].cPropertyIDs; 
  1531.                     ulOutIndex++;
  1532.                 }
  1533.             }
  1534.         }
  1535.             
  1536.         // Allocate a Description Buffer if needed
  1537.         if( ppDescBuffer )
  1538.         {
  1539.             ULONG cBuffers = CalcDescripBuffers(cSets, pPropInfoSet);
  1540.             if( cBuffers != 0 )
  1541.             {
  1542.                 pDescBuffer = (WCHAR*)CoTaskMemAlloc(cBuffers * cchDescBuffSize * sizeof(WCHAR));
  1543.                 if(pDescBuffer == NULL)
  1544.                 {
  1545.                     hr = E_OUTOFMEMORY;
  1546.                     goto EXIT;
  1547.                 }
  1548.                 *ppDescBuffer = pDescBuffer;
  1549.                 memset(pDescBuffer, 0, (cBuffers * cchDescBuffSize * sizeof(WCHAR)));
  1550.             }
  1551.         }
  1552.  
  1553.         // Process requested or derived Property sets
  1554.         dwStatus = 0;
  1555.         for(ulSet=0; ulSet<cSets; ulSet++)
  1556.         {
  1557.             ulNext=0;
  1558.             cPropInfos = 0;
  1559.             pPropInfo = NULL;
  1560.             dwStatus &= (GETPROPINFO_ERRORSOCCURRED | GETPROPINFO_VALIDPROP);
  1561.  
  1562.             // Calculate the number of property nodes needed for this
  1563.             // property set.
  1564.             if( cPropertySets == 0 )
  1565.             {
  1566.                 ULONG ulTempSet;
  1567.                 if (pGuid != NULL)
  1568.                     ulTempSet = ulIndex;
  1569.                 else
  1570.                     ulTempSet = ulSet;
  1571.  
  1572.                 cPropInfos = m_pUPropSet[ulTempSet].cUPropInfo;
  1573.                 dwStatus |= GETPROPINFO_ALLPROPIDS;
  1574.                 m_rgiPropSetDex[0] = ulTempSet;
  1575.                 m_cPropSetDex = 1;
  1576.             }
  1577.             else
  1578.             {
  1579.                 // If the count of PROPIDs is 0 (NOTE: the above routine already determined
  1580.                 // if it belonged to a category and if so set the count of properties to 0 for
  1581.                 // each propset in that category.
  1582.                 if( pPropInfoSet[ulSet].cPropertyInfos == 0 )
  1583.                 {
  1584.                     dwStatus |= GETPROPINFO_ALLPROPIDS;
  1585.                     // We have to determine if the property set is supported and if so
  1586.                     // the count of properties in the set.
  1587.                     if( GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_OK)                
  1588.                     {
  1589.                         ATLASSERT( m_cPropSetDex == 1 );
  1590.                         
  1591.                         cPropInfos += m_pUPropSet[m_rgiPropSetDex[0]].cUPropInfo;
  1592.                     }
  1593.                     else
  1594.                     {
  1595.                         // Not Supported                    
  1596.                         dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1597.                         goto NEXT_SET;
  1598.                     }
  1599.                 }
  1600.                 else
  1601.                 {
  1602.                     // We also handle the case here where the user has requested
  1603.                     // a non-initialization group property info set while the
  1604.                     // provider is not initialized.  In this case, properties should
  1605.                     // not be set.
  1606.                     cPropInfos = pPropInfoSet[ulSet].cPropertyInfos;
  1607.                     if( (GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_FALSE)
  1608.                         || (!bInitialized && 
  1609.                         !(InlineIsEqualGUID(pPropInfoSet[ulSet].guidPropertySet, DBPROPSET_DBINIT)) &&
  1610.                         !(InlineIsEqualGUID(pPropInfoSet[ulSet].guidPropertySet, DBPROPSET_DBINITALL))))
  1611.                     {
  1612.                         dwStatus |= GETPROPINFO_NOTSUPPORTED;
  1613.                         dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1614.                     }
  1615.                 }
  1616.             }
  1617.  
  1618.  
  1619.             // Allocate DBPROP array
  1620.             ATLASSERT( cPropInfos != 0 );
  1621.             pPropInfo = (DBPROPINFO*)CoTaskMemAlloc(cPropInfos * sizeof(DBPROPINFO));
  1622.             if( pPropInfo )
  1623.             {
  1624.                 // Initialize Buffer
  1625.                 memset(pPropInfo, 0, cPropInfos * sizeof(DBPROPINFO));
  1626.                 for(ULONG ulProp=0; ulProp<cPropInfos; ulProp++)
  1627.                 {
  1628.                     VariantInit(&(pPropInfo[ulProp].vValues));
  1629.                     if( dwStatus & GETPROPINFO_NOTSUPPORTED )
  1630.                     {
  1631.                         // Not supported, thus we need to mark all as NOT_SUPPORTED
  1632.                         pPropInfo[ulProp].dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  1633.                         pPropInfo[ulProp].dwFlags = DBPROPFLAGS_NOTSUPPORTED;
  1634.                         dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1635.                     }                    
  1636.                 }
  1637.                 // Make sure we support the property set
  1638.                 if( dwStatus & GETPROPINFO_NOTSUPPORTED )
  1639.                 {
  1640.                     ulNext = cPropInfos;
  1641.                     goto NEXT_SET;
  1642.                 }
  1643.  
  1644.                 // Retrieve the property information for this property set
  1645.                 for(ul=0; ul<m_cPropSetDex; ul++)
  1646.                 {
  1647.                     pUPropInfo = (m_pUPropSet[m_rgiPropSetDex[ul]].pUPropInfo);
  1648.                     ATLASSERT( pUPropInfo );
  1649.                                 
  1650.                     // Retrieve current value of properties
  1651.                     if( dwStatus & GETPROPINFO_ALLPROPIDS )
  1652.                     {
  1653.                         for(ulProp=0; ulProp<m_pUPropSet[m_rgiPropSetDex[ul]].cUPropInfo; ulProp++)
  1654.                         {
  1655.                             // Verify property is supported, if not do not return 
  1656.                             if( !TESTBIT(&(m_rgdwSupported[m_rgiPropSetDex[ul] * m_cElemPerSupported]), ulProp) )
  1657.                                 continue;
  1658.  
  1659.                             pCurPropInfo = &(pPropInfo[ulNext]);
  1660.  
  1661.                             // If the ppDescBuffer pointer was not NULL, then
  1662.                             // we need supply description of the properties
  1663.                             if( ppDescBuffer )
  1664.                             {
  1665.                                 // Set Buffer pointer
  1666.                                 pCurPropInfo->pwszDescription = pDescBuffer;
  1667.  
  1668.                                 // Load the string into temp buffer
  1669.                                 cch = LoadDescription(pUPropInfo[ulProp].ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff)));
  1670.                                 if( cch )
  1671.                                 {
  1672.                                     // Adjust for '\0'
  1673.                                     cch++;
  1674.  
  1675.                                     // Transfer to official buffer if room
  1676.                                     memcpy(pDescBuffer, wszBuff, cch * sizeof(WCHAR));
  1677.                                     pDescBuffer += cch;
  1678.                                 }
  1679.                                 else
  1680.                                 {
  1681.                                     wcscpy(pDescBuffer, L"UNKNOWN");
  1682.                                     pDescBuffer += (wcslen(L"UNKNOWN") + 1);
  1683.                                 }
  1684.                             }
  1685.  
  1686.                             pCurPropInfo->dwPropertyID = pUPropInfo[ulProp].dwPropId;
  1687.                             pCurPropInfo->dwFlags = pUPropInfo[ulProp].dwFlags;
  1688.                             pCurPropInfo->vtType = pUPropInfo[ulProp].VarType;
  1689.                             pCurPropInfo->vValues.vt = VT_EMPTY;
  1690.  
  1691.                             dwStatus |= GETPROPINFO_VALIDPROP;
  1692.                             // Increment to next available buffer
  1693.                             ulNext++;
  1694.                         }
  1695.                     }
  1696.                     else
  1697.                     {
  1698.                         ATLASSERT( m_cPropSetDex == 1 );
  1699.  
  1700.                         for( ulProp = 0; ulProp < cPropInfos; ulProp++, ulNext++ )
  1701.                         {
  1702.                             pCurPropInfo = &(pPropInfo[ulNext]);
  1703.  
  1704.                             // Process Properties based on Restriction array.
  1705.                             pCurPropInfo->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  1706.                         
  1707.                             if( GetUPropInfoPtr(m_rgiPropSetDex[ul], pCurPropInfo->dwPropertyID, &pUPropInfo)
  1708.                                 == S_OK )
  1709.                             {
  1710.                                 // If the ppDescBuffer pointer was not NULL, then
  1711.                                 // we need supply description of the properties
  1712.                                 if( ppDescBuffer )
  1713.                                 {
  1714.                                     // Set Buffer pointer
  1715.                                     pCurPropInfo->pwszDescription = pDescBuffer;
  1716.  
  1717.                                     // Load the string into temp buffer
  1718.                                     cch = LoadDescription(pUPropInfo->ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff)));
  1719.                                     if( cch )
  1720.                                     {
  1721.                                         // Adjust for '\0'
  1722.                                         cch++;
  1723.  
  1724.                                         // Transfer to official buffer if room
  1725.                                         memcpy(pDescBuffer, wszBuff, cch * sizeof(WCHAR));
  1726.                                         pDescBuffer += cch;
  1727.                                     }
  1728.                                     else
  1729.                                     {
  1730.                                         wcscpy(pDescBuffer, L"UNKNOWN");
  1731.                                         pDescBuffer += (wcslen(L"UNKNOWN") + 1);
  1732.                                     }
  1733.                                 }
  1734.  
  1735.                                 pCurPropInfo->dwPropertyID = pUPropInfo->dwPropId;
  1736.                                 pCurPropInfo->dwFlags = pUPropInfo->dwFlags;
  1737.                                 pCurPropInfo->vtType = pUPropInfo->VarType;
  1738.  
  1739.                                 dwStatus |= GETPROPINFO_VALIDPROP;
  1740.                             }
  1741.                             else
  1742.                             {
  1743.                                 // Not Supported
  1744.                                 pCurPropInfo->dwFlags = DBPROPFLAGS_NOTSUPPORTED;
  1745.                                 dwStatus |= GETPROPINFO_ERRORSOCCURRED;
  1746.                             }
  1747.                         }
  1748.                     }
  1749.                 }
  1750.             }
  1751.             else
  1752.             {
  1753.                 hr = E_OUTOFMEMORY;
  1754.                 goto EXIT;
  1755.             }
  1756.  
  1757. NEXT_SET:
  1758.             pPropInfoSet[ulSet].cPropertyInfos = ulNext;
  1759.             pPropInfoSet[ulSet].rgPropertyInfos = pPropInfo;
  1760.         }
  1761.  
  1762.         // Success, set return values
  1763.         *pcPropertyInfoSets = cSets;
  1764.         *prgPropertyInfoSets = pPropInfoSet;
  1765.  
  1766.         // At least one propid was marked as not S_OK
  1767.         if( dwStatus & GETPROPINFO_ERRORSOCCURRED )
  1768.         {
  1769.             // If at least 1 property was set
  1770.             if( dwStatus & GETPROPINFO_VALIDPROP )
  1771.                 return DB_S_ERRORSOCCURRED;
  1772.             else
  1773.             {
  1774.                 // Do not free any of the rgPropertyInfoSets, but
  1775.                 // do free the ppDescBuffer
  1776.                 if( pDescBuffer )
  1777.                 {
  1778.                     ATLASSERT( ppDescBuffer );
  1779.                     CoTaskMemFree(pDescBuffer);
  1780.                     *ppDescBuffer = NULL;
  1781.                 }
  1782.                 return DB_E_ERRORSOCCURRED;
  1783.             }
  1784.         }
  1785.  
  1786.         return S_OK;
  1787. EXIT:
  1788.         // Check if failure and clean up any allocated memory
  1789.         if( FAILED(hr) && 
  1790.             (hr != DB_E_ERRORSOCCURRED) )
  1791.         {
  1792.             // Free Description Buffer
  1793.             if( pDescBuffer )
  1794.             {
  1795.                 ATLASSERT( ppDescBuffer );
  1796.  
  1797.                 CoTaskMemFree(pDescBuffer);
  1798.                 *ppDescBuffer = NULL;
  1799.             }
  1800.  
  1801.             if( pPropInfoSet )
  1802.             {
  1803.                 // Loop through Property Sets
  1804.                 for(ulSet=0; ulSet<cSets; ulSet++)
  1805.                 {
  1806.                     if( pPropInfoSet[ulSet].rgPropertyInfos )
  1807.                         CoTaskMemFree(pPropInfoSet[ulSet].rgPropertyInfos);
  1808.                 }
  1809.  
  1810.                 CoTaskMemFree(pPropInfoSet);
  1811.             }
  1812.         }
  1813.         
  1814.         return hr;
  1815.     }
  1816.  
  1817.     ULONG m_cUPropSet; //count of UPropSet items
  1818.     UPROPSET* m_pUPropSet; //Pointer to UPropset items
  1819.     UPROPSET* m_pUPropSetToDel; //Pointer to UPropset items
  1820.     ULONG m_cPropSetDex;     //count of UPropSet Indexes
  1821.     ULONG* m_rgiPropSetDex;//array of UPropSet Index values
  1822.     ULONG m_cElemPerSupported; //number of DWORDS per UPropSet to indicate supported UPropIds
  1823.     DWORD* m_rgdwSupported;//array of DWORDs indicating supported UPropIds 
  1824.  
  1825.     HRESULT    InitAvailUPropSets(ULONG* pcUPropSet, UPROPSET** ppUPropSet, ULONG* pcElemPerSupported, GUID* pguid)
  1826.     {
  1827.         ATLASSERT(pcUPropSet && ppUPropSet);
  1828.         int cSets = (int)T::_GetPropSet(NULL, pcElemPerSupported);
  1829.         UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  1830.         if (pSet == NULL) 
  1831.             return E_OUTOFMEMORY;
  1832.         *ppUPropSet = T::_GetPropSet(pcUPropSet, pcElemPerSupported, pSet, pguid);
  1833.         m_pUPropSetToDel = pSet;
  1834.         return S_OK;
  1835.     }
  1836.     virtual HRESULT    InitUPropSetsSupported()
  1837.     {
  1838.         ULONG cPropSet = 0, cElemsPerSupported = 0;
  1839.         int cSets = (int)T::_GetPropSet(NULL, &cElemsPerSupported);
  1840.         UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  1841.         if (pSet == NULL) 
  1842.             return E_OUTOFMEMORY;
  1843.         pSet = T::_GetPropSet(&cPropSet, &cElemsPerSupported, pSet);
  1844.         memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD));
  1845.         CoTaskMemFree(pSet);
  1846.         return S_OK;
  1847.     }
  1848.     //Load a localized description
  1849.     int    LoadDescription(ULONG ids, PWSTR pwszBuff, ULONG cchBuff)
  1850.     {
  1851.         return LoadStringW(_Module.GetResourceInstance(), ids, pwszBuff, cchBuff);
  1852.     }
  1853. };
  1854.  
  1855. // Implementation Class 
  1856. template <class T>
  1857. class CUtlProps    : public CBitFieldOps, public CDBIDOps
  1858. {
  1859. public:
  1860.     ULONG m_cUPropSet; //count of UPropSet items
  1861.     UPROPSET* m_pUPropSet; //Pointer to UPropset items
  1862.     UPROP* m_pUProp;
  1863.     ULONG m_cUPropSetHidden; //Count of Hidden items
  1864.     DWORD m_dwFlags; //Configuration flags
  1865.     ULONG m_cPropSetDex; //count of UPropSet Indexes
  1866.     ULONG* m_rgiPropSetDex; //pointer to Array of UPropSet Index values
  1867.     ULONG m_cElemPerSupported;//number of DWORDS per UPropSet to indicate supported UPropIds
  1868.     DWORD* m_rgdwSupported; //pointer to array of DWORDs indicating supported UPropIds 
  1869.     DWORD* m_rgdwPropsInError;//pointer to array of DWORDs indicating if property is in error
  1870.  
  1871.     enum EnumUPropSetFlags
  1872.     {
  1873.         UPROPSET_HIDDEN                = 0x00000001,
  1874.         UPROPSET_PASSTHROUGH        = 0x00000002
  1875.     };
  1876.     enum EnumGetProp
  1877.     {
  1878.         GETPROP_ALLPROPIDS            = 0x0001,
  1879.         GETPROP_NOTSUPPORTED        = 0x0002,
  1880.         GETPROP_ERRORSOCCURRED        = 0x0004,
  1881.         GETPROP_VALIDPROP            = 0x0008,
  1882.         GETPROP_PROPSINERROR        = 0x0010
  1883.     };
  1884.  
  1885.     enum EnumSetProp
  1886.     {
  1887.         SETPROP_BADOPTION            = 0x0001,
  1888.         SETPROP_NOTSUPPORTED        = 0x0002,
  1889.         SETPROP_VALIDPROP            = 0x0004,
  1890.         SETPROP_ERRORS                = 0x0008,
  1891.         SETPROP_COLUMN_LEVEL        = 0x0010,
  1892.         SETPROP_WAS_REQUIRED        = 0x0020
  1893.     };
  1894.  
  1895.     CUtlProps(DWORD dwFlags = 0)
  1896.     {
  1897.         ClearMemberVars();
  1898.         m_dwFlags = dwFlags;
  1899.     }
  1900.     ~CUtlProps()
  1901.     {
  1902.         FreeMemory();
  1903.     }
  1904.     void FreeMemory()
  1905.     {
  1906.         // Remove Property Information
  1907.         if( m_pUProp )
  1908.         {
  1909.             for(ULONG ulPropSet=0; ulPropSet<m_cUPropSet; ulPropSet++)
  1910.             {
  1911.                 UPROPVAL* pUPropVal = m_pUProp[ulPropSet].pUPropVal;
  1912.                 for(ULONG ulPropId=0; ulPropId<m_pUProp[ulPropSet].cPropIds; ulPropId++)
  1913.                 {
  1914.                     delete pUPropVal[ulPropId].pCColumnIds;
  1915.                     VariantClear(&(pUPropVal[ulPropId].vValue));
  1916.                 }
  1917.                 delete[] m_pUProp[ulPropSet].rgpUPropInfo;
  1918.                 delete[] m_pUProp[ulPropSet].pUPropVal;
  1919.             }
  1920.         
  1921. //            delete[] m_pUProp;
  1922.         }
  1923.         
  1924.         delete[] m_rgdwSupported;
  1925.         delete[] m_rgdwPropsInError;
  1926.         delete[] m_rgiPropSetDex;
  1927.  
  1928.         ClearMemberVars();
  1929.     }
  1930.     void ClearMemberVars()
  1931.     {
  1932.         m_cPropSetDex        = 0;
  1933.         m_cUPropSet            = 0;
  1934.         m_cUPropSetHidden    = 0;
  1935.         m_pUPropSet            = NULL;
  1936.  
  1937.         m_dwFlags            = 0;
  1938.  
  1939.         m_pUProp            = NULL;
  1940.         m_cElemPerSupported    = 0;
  1941.         m_rgdwSupported        = NULL;
  1942.         m_rgdwPropsInError    = NULL;
  1943.         m_rgiPropSetDex        = NULL;
  1944.     }
  1945.  
  1946.     void RetrieveColumnIdProps(DBPROP* pCurProp, UPROPVAL* pUPropVal, ULONG* pulNext)
  1947.     {
  1948.         // Reset to first Node
  1949.         CColumnIds* pColIds = pUPropVal->pCColumnIds;
  1950.         HRESULT hr = E_FAIL;
  1951.         for (int i = 0; i < pColIds->GetSize(); i++)
  1952.         {
  1953.             CPropColID colId; 
  1954.             hr = pColIds->GetValue(i, &(pCurProp->dwOptions), &(pCurProp->colid),&(pCurProp->vValue));
  1955.             if (SUCCEEDED(hr))
  1956.                 pCurProp = &(pCurProp[++(*pulNext)]);
  1957.         }
  1958.         (*pulNext)++;
  1959.     }
  1960.     ULONG GetCountofWritablePropsInPropSet(ULONG iPropSet)
  1961.     {
  1962.         ULONG cWritable = 0;
  1963.         UPROPINFO* pUPropInfo;
  1964.  
  1965.         ATLASSERT( m_pUPropSet );
  1966.         ATLASSERT( iPropSet < m_cUPropSet );
  1967.  
  1968.         pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo;
  1969.         
  1970.         for(ULONG ul=0; ul<m_pUPropSet[iPropSet].cUPropInfo; ul++)
  1971.         {
  1972.             if( pUPropInfo[ul].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  1973.                 cWritable++;
  1974.         }
  1975.         
  1976.         return cWritable;
  1977.     }
  1978.     ULONG GetCountofColids(UPROP* pUProp)
  1979.     {
  1980.         ULONG    cExtra=0;
  1981.         ATLASSERT(pUProp);
  1982.         for(ULONG ul=0; ul<pUProp->cPropIds; ul++)
  1983.         {
  1984.             if( pUProp->pUPropVal[ul].pCColumnIds )
  1985.                 cExtra += (pUProp->pUPropVal[ul].pCColumnIds)->GetCountOfPropColids();
  1986.         }
  1987.         return cExtra;
  1988.     }
  1989.     ULONG GetUPropValIndex(ULONG iCurSet, DBPROPID dwPropId)
  1990.     {
  1991.         for(ULONG ul=0; ul<m_pUProp[iCurSet].cPropIds; ul++)
  1992.         {
  1993.             if( (m_pUProp[iCurSet].rgpUPropInfo[ul])->dwPropId == dwPropId )
  1994.                 return ul;
  1995.         }
  1996.         return 0;
  1997.     }
  1998.     HRESULT    SetProperty(ULONG iCurSet, ULONG iCurProp, DBPROP* pDBProp)
  1999.     {
  2000.         HRESULT    hr = S_OK;
  2001.         UPROP* pUProp;
  2002.         UPROPVAL* pUPropVal;
  2003.         UPROPINFO* pUPropInfo;
  2004.         ULONG iUProp;
  2005.  
  2006.         ATLASSERT( pDBProp );
  2007.  
  2008.         // Set pointer to correct set
  2009.         pUProp = &(m_pUProp[iCurSet]);
  2010.         ATLASSERT( pUProp );
  2011.  
  2012.         pUPropInfo = &(m_pUPropSet[iCurSet].pUPropInfo[iCurProp]);
  2013.         ATLASSERT( pUPropInfo );
  2014.  
  2015.         // Determine the index within m_pUProp    
  2016.         for(iUProp=0; iUProp<pUProp->cPropIds; iUProp++)
  2017.         {
  2018.             if( (pUProp->rgpUPropInfo[iUProp])->dwPropId == pDBProp->dwPropertyID )
  2019.                 break; 
  2020.         }
  2021.  
  2022.         if( iUProp >= pUProp->cPropIds )
  2023.         {
  2024.             ATLASSERT( !"Should have found index of property to set" );
  2025.             hr = E_FAIL;
  2026.             pDBProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  2027.             goto EXIT;
  2028.         }
  2029.  
  2030.         //Get the UPROPVAL node pointer within that propset.
  2031.         pUPropVal = &(pUProp->pUPropVal[iUProp]);
  2032.         ATLASSERT( pUPropVal );
  2033.  
  2034.         // Handle VT_EMPTY, which indicates to the provider to 
  2035.         // reset this property to the providers default
  2036.         if( pDBProp->vValue.vt == VT_EMPTY )
  2037.         {
  2038.             if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  2039.             {
  2040.                 // Remove any nodes, because the default applies to 
  2041.                 // all columns
  2042.                 delete pUPropVal->pCColumnIds;            
  2043.                 pUPropVal->pCColumnIds = NULL;            
  2044.             }
  2045.  
  2046.             // Should clear here, since previous values may already
  2047.             // have been cached and need to be replaced.
  2048.             VariantClear(&(pUPropVal->vValue));
  2049.  
  2050.             pUPropVal->dwFlags &= ~DBINTERNFLAGS_CHANGED;
  2051.             hr = GetDefaultValue(iCurSet, pDBProp->dwPropertyID, 
  2052.                 &(pUPropVal->dwOption), &(pUPropVal->vValue));
  2053.  
  2054.             goto EXIT;
  2055.         }
  2056.             
  2057.  
  2058.         // Column Level
  2059.         if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  2060.         {
  2061.             // Check to see if it applies to all
  2062.             if( (CompareDBIDs(&(pDBProp->colid), &DB_NULLID) == S_OK) )
  2063.             {
  2064.                 // Remove the Columns Storage object
  2065.                 delete pUPropVal->pCColumnIds;
  2066.                 pUPropVal->pCColumnIds = NULL;            
  2067.                 pUPropVal->dwOption = pDBProp->dwOptions;
  2068.                 if( FAILED(hr = VariantCopy(&(pUPropVal->vValue), 
  2069.                     &(pDBProp->vValue))) )
  2070.                     goto EXIT;
  2071.                 pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
  2072.             }    
  2073.             else // Does not apply to all columns
  2074.             {
  2075.                 if( pUPropVal->pCColumnIds == NULL )
  2076.                     ATLTRY(pUPropVal->pCColumnIds = new CColumnIds)
  2077.                 
  2078.                 if( pUPropVal->pCColumnIds )
  2079.                 {
  2080.                     if( FAILED(hr = (pUPropVal->pCColumnIds)->AddColumnId(pDBProp)) )
  2081.                         goto EXIT;
  2082.                     pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
  2083.                 }            
  2084.                 else
  2085.                 {
  2086.                     hr = E_OUTOFMEMORY;
  2087.                     goto EXIT;
  2088.                 }
  2089.  
  2090.             }
  2091.         }    
  2092.         else
  2093.         {
  2094.             // Set for non-column level properties
  2095.             pUPropVal->dwOption = pDBProp->dwOptions;
  2096.             if( FAILED(hr = VariantCopy(&(pUPropVal->vValue), 
  2097.                 &(pDBProp->vValue))) )
  2098.                 goto EXIT;
  2099.             OnPropertyChanged(iCurSet, pDBProp);
  2100.             pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
  2101.         }
  2102.  
  2103. EXIT:
  2104.         if( SUCCEEDED(hr) )
  2105.             pDBProp->dwStatus = DBPROPSTATUS_OK;
  2106.  
  2107.         return hr;
  2108.     }
  2109.     //Retrieve the property set indexes that match this property set.
  2110.     HRESULT    GetPropertySetIndex(GUID* pPropertySet)
  2111.     {
  2112.         DWORD    dwFlag = 0;
  2113.         ULONG    ulSet;
  2114.  
  2115.         ATLASSERT( m_cUPropSet && m_pUPropSet );
  2116.         ATLASSERT( m_rgiPropSetDex );
  2117.         ATLASSERT( pPropertySet );
  2118.  
  2119.         m_cPropSetDex = 0;
  2120.  
  2121.         if( *pPropertySet == DBPROPSET_DATASOURCEALL )
  2122.         {
  2123.             dwFlag = DBPROPFLAGS_DATASOURCE;
  2124.         }
  2125.         else if( *pPropertySet == DBPROPSET_DATASOURCEINFOALL )
  2126.         {
  2127.             dwFlag = DBPROPFLAGS_DATASOURCEINFO;
  2128.         }
  2129.         else if( *pPropertySet == DBPROPSET_ROWSETALL )
  2130.         {
  2131.             dwFlag = DBPROPFLAGS_ROWSET;
  2132.         }
  2133.         else if( *pPropertySet == DBPROPSET_DBINITALL )
  2134.         {
  2135.             dwFlag = DBPROPFLAGS_DBINIT;
  2136.         }
  2137.         else if( *pPropertySet == DBPROPSET_SESSIONALL )
  2138.         {
  2139.             dwFlag = DBPROPFLAGS_SESSION;
  2140.         }
  2141.         else // No scan required, just look for match.
  2142.         {
  2143.             for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  2144.             {
  2145.                 if( *(m_pUPropSet[ulSet].pPropSet) == *pPropertySet )
  2146.                 {
  2147.                     m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  2148.                     m_cPropSetDex++;
  2149.                     break;
  2150.                 }
  2151.             }
  2152.             goto EXIT;
  2153.         }
  2154.  
  2155.         // Scan through the property sets looking for matching attributes
  2156.         for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
  2157.         {
  2158.             if( m_pUPropSet[ulSet].pUPropInfo[0].dwFlags & dwFlag )
  2159.             {
  2160.                 m_rgiPropSetDex[m_cPropSetDex] = ulSet;
  2161.                 m_cPropSetDex++;
  2162.             }
  2163.         }
  2164.  
  2165. EXIT:
  2166.         return (m_cPropSetDex) ? S_OK : S_FALSE;
  2167.     }
  2168.  
  2169.  
  2170.     HRESULT    FInit(CUtlProps* pCopyMe = NULL)
  2171.     {
  2172.         HRESULT        hr;
  2173.         ULONG        ulPropId;
  2174.         ULONG        cPropIds;
  2175.         ULONG        iPropSet;
  2176.         ULONG        iNewDex;
  2177.         UPROPINFO**    rgpUPropInfo;
  2178.         UPROPVAL*    rgUPropVal;
  2179.         UPROPINFO*    pUPropInfo;
  2180.         
  2181.         // If a pointer is passed in, we should copy that property object
  2182.         if( pCopyMe )
  2183.         {
  2184.             // Establish some base values
  2185.             m_cUPropSet = pCopyMe->m_cUPropSet;
  2186.             m_pUPropSet = pCopyMe->m_pUPropSet;
  2187.             m_cElemPerSupported = pCopyMe->m_cElemPerSupported;
  2188.             ATLASSERT( (m_cUPropSet != 0)  && (m_cElemPerSupported != 0) );
  2189.             // Retrieve Supported Bitmask
  2190.             ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2191.             ATLTRY(m_rgdwPropsInError = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2192.             if( m_rgdwSupported == NULL|| m_rgdwPropsInError == NULL)
  2193.             {
  2194.                 delete[] m_rgdwSupported;
  2195.                 delete[] m_rgdwPropsInError;
  2196.                 return E_OUTOFMEMORY;
  2197.             }
  2198.             ClearPropertyInError();
  2199.             pCopyMe->CopyUPropSetsSupported(m_rgdwSupported);
  2200.  
  2201.         }
  2202.         else
  2203.         {
  2204.             int cSets = (int)T::_GetPropSet(NULL, &m_cElemPerSupported);
  2205.             UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  2206.             if (pSet == NULL) 
  2207.                 return E_OUTOFMEMORY;
  2208.             pSet = T::_GetPropSet(&m_cUPropSet, &m_cElemPerSupported, pSet);
  2209.             if (m_pUPropSet != NULL)
  2210.                 CoTaskMemFree(m_pUPropSet);
  2211.             m_pUPropSet = pSet;
  2212.             ATLASSERT( (m_cUPropSet != 0)  && (m_cElemPerSupported != 0) );
  2213.             if( !m_cUPropSet || !m_cElemPerSupported )
  2214.                 return E_FAIL;
  2215.  
  2216.             ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2217.             ATLTRY(m_rgdwPropsInError = new DWORD[m_cUPropSet * m_cElemPerSupported])
  2218.             if( m_rgdwSupported == NULL || m_rgdwPropsInError == NULL)
  2219.             {
  2220.                 delete[] m_rgdwSupported;
  2221.                 delete[] m_rgdwPropsInError;
  2222.                 return E_OUTOFMEMORY;
  2223.             }
  2224.             else
  2225.                 ClearPropertyInError();
  2226.  
  2227.             if( FAILED(hr = InitUPropSetsSupported()) )
  2228.             {
  2229.                 delete[] m_rgdwSupported;
  2230.                 m_rgdwSupported = NULL;
  2231.                 return hr;
  2232.             }
  2233.         }
  2234.  
  2235.         // Allocate UPROPS structures for the count of Property sets
  2236.         ATLTRY(m_pUProp = (UPROP*) new UPROP[m_cUPropSet])
  2237.         if( m_pUProp)
  2238.         {
  2239.             memset(m_pUProp, 0, m_cUPropSet * sizeof(UPROP));
  2240.         }
  2241.         else
  2242.         {
  2243.             m_cUPropSet = 0;
  2244.             return E_OUTOFMEMORY;
  2245.         }
  2246.  
  2247.         // With in the UPROPS Structure allocate and intialize the
  2248.         // Property IDs that belong to this property set.
  2249.         for(iPropSet=0; iPropSet<m_cUPropSet; iPropSet++)
  2250.         {
  2251.             cPropIds = GetCountofWritablePropsInPropSet(iPropSet);
  2252.  
  2253.             if( cPropIds > 0 )
  2254.             {
  2255.                 ATLTRY(rgpUPropInfo = (UPROPINFO**) new UPROPINFO*[cPropIds])
  2256.                 ATLTRY(rgUPropVal = (UPROPVAL*) new UPROPVAL[cPropIds])
  2257.                 if( rgpUPropInfo != NULL && rgUPropVal != NULL)
  2258.                 {
  2259.                     if( pCopyMe )
  2260.                     {
  2261.                         pCopyMe->CopyUPropInfo(iPropSet, rgpUPropInfo);
  2262.                         if( FAILED(hr = pCopyMe->CopyUPropVal(iPropSet, rgUPropVal)) )
  2263.                             return hr;
  2264.                     }
  2265.                     else
  2266.                     {
  2267.                         // Clear Pointer Array
  2268.                         memset(rgpUPropInfo, 0, cPropIds * sizeof(UPROPINFO*));
  2269.  
  2270.                         // Set Pointer to correct property ids with a property set
  2271.                         pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo;
  2272.  
  2273.                         // Set up the writable property buffers
  2274.                         iNewDex = 0;
  2275.                         for(ulPropId=0; ulPropId<m_pUPropSet[iPropSet].cUPropInfo; ulPropId++)
  2276.                         {
  2277.                             if( pUPropInfo[ulPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2278.                             {
  2279.                                 // Following ATLASSERT indicates that the are more
  2280.                                 // writable properties then space allocated
  2281.                                 ATLASSERT(iNewDex < cPropIds);
  2282.  
  2283.                                 rgpUPropInfo[iNewDex] = &(pUPropInfo[ulPropId]);
  2284.                                 rgUPropVal[iNewDex].dwOption = DBPROPOPTIONS_SETIFCHEAP;
  2285.                                 rgUPropVal[iNewDex].pCColumnIds = NULL;
  2286.                                 rgUPropVal[iNewDex].dwFlags = 0;
  2287.                                 VariantInit(&(rgUPropVal[iNewDex].vValue));
  2288.                                 GetDefaultValue(iPropSet, pUPropInfo[ulPropId].dwPropId, 
  2289.                                     &(rgUPropVal[iNewDex].dwOption), &(rgUPropVal[iNewDex].vValue));
  2290.                                 iNewDex++;
  2291.                             }
  2292.                         }
  2293.                         
  2294.                         ATLASSERT(cPropIds == iNewDex);
  2295.                     }
  2296.  
  2297.                     m_pUProp[iPropSet].rgpUPropInfo = rgpUPropInfo;
  2298.                     m_pUProp[iPropSet].pUPropVal = rgUPropVal;
  2299.                     m_pUProp[iPropSet].cPropIds = cPropIds;
  2300.                 }
  2301.                 else
  2302.                 {
  2303.                     delete[] rgpUPropInfo;
  2304.                     delete[] rgUPropVal;
  2305.                     return E_OUTOFMEMORY;
  2306.                 }
  2307.             }
  2308.         }
  2309.  
  2310.         // Finally determine if there are any hidden property sets..  Those
  2311.         // that do not show up in GetPropertyInfo and should not be returns on 
  2312.         // a 0, NULL call to GetProperties
  2313.         for(iPropSet=0; iPropSet<m_cUPropSet; iPropSet++)
  2314.         {
  2315.             if( m_pUPropSet[iPropSet].dwFlags & UPROPSET_HIDDEN )
  2316.                 m_cUPropSetHidden++;
  2317.         }
  2318.  
  2319.         return S_OK;
  2320.     }
  2321.     HRESULT    FillDefaultValues(ULONG ulPropSetTarget = ULONG_MAX)
  2322.     {
  2323.         HRESULT        hr;
  2324.         ULONG        ulPropId;
  2325.         ULONG        iPropSet;
  2326.         ULONG        iNewDex;
  2327.  
  2328.         // Fill in all the actual values.
  2329.         // Typically because we now have an hdbc with which to get them.
  2330.         // (Or we no longer have an hdbc, so must clear them.)
  2331.         // Note that the UPROP (with values) array may be a subset of the UPROPINFO array.
  2332.         // Only writable properties are in UPROP array.
  2333.  
  2334.         // Maybe restrict to a single PropSet if within valid range [0...m_cUPropSet-1].
  2335.         // Otherwise do all propsets.
  2336.         iPropSet = (ulPropSetTarget < m_cUPropSet) ? ulPropSetTarget : 0;
  2337.  
  2338.         for( ; iPropSet<m_cUPropSet; iPropSet++)
  2339.         {
  2340.             iNewDex = 0;
  2341.             for(ulPropId=0; ulPropId<m_pUPropSet[iPropSet].cUPropInfo; ulPropId++)
  2342.             {
  2343.                 if( m_pUPropSet[iPropSet].pUPropInfo[ulPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2344.                 {
  2345.                     //Initialize dwFlags element of UPropVal
  2346.                     m_pUProp[iPropSet].pUPropVal[iNewDex].dwFlags = 0;
  2347.  
  2348.                     // Don't need this since SetProperties() resets these.
  2349.                     //ATLASSERT( m_pUProp[iPropSet].pUPropVal[iNewDex].dwOption == DBPROPOPTIONS_SETIFCHEAP);
  2350.                     ATLASSERT( m_pUProp[iPropSet].pUPropVal[iNewDex].pCColumnIds == NULL);
  2351.  
  2352.                     VariantClear(&m_pUProp[iPropSet].pUPropVal[iNewDex].vValue);
  2353.                     hr = GetDefaultValue(
  2354.                             iPropSet, 
  2355.                             m_pUPropSet[iPropSet].pUPropInfo[ulPropId].dwPropId, 
  2356.                             &m_pUProp[iPropSet].pUPropVal[iNewDex].dwOption, 
  2357.                             &m_pUProp[iPropSet].pUPropVal[iNewDex].vValue );
  2358.                     if (FAILED(hr))
  2359.                         return hr;
  2360.                     iNewDex++;
  2361.                 }
  2362.             }
  2363.  
  2364.             // We're through if restricting to single PropSet.
  2365.             if (ulPropSetTarget < m_cUPropSet)
  2366.                 break;
  2367.         }
  2368.         return NOERROR;
  2369.     }
  2370.  
  2371.     // Translate Rowset IIDs to PROPSET structures ready to pass to SetProperties
  2372.     HRESULT    ConvertRowsetIIDtoDBPROPSET(const IID* piid, DBPROPSET* pPropSet)
  2373.     {
  2374.         HRESULT        hr = S_OK;
  2375.         DBPROP*        pProp;
  2376.  
  2377.         ATLASSERT( piid || pPropSet );
  2378.         ATLASSERT( (pPropSet->cProperties == 1) || (pPropSet->rgProperties) );
  2379.  
  2380.         pProp = &(pPropSet->rgProperties[0]);
  2381.  
  2382.         if(InlineIsEqualGUID(*piid, IID_IAccessor))
  2383.             pProp->dwPropertyID = DBPROP_IAccessor;
  2384.         else if(InlineIsEqualGUID(*piid,IID_IColumnsInfo))
  2385.             pProp->dwPropertyID = DBPROP_IColumnsInfo;
  2386.         else if(InlineIsEqualGUID(*piid , IID_IRowset))
  2387.             pProp->dwPropertyID = DBPROP_IRowset;
  2388.         else if(InlineIsEqualGUID(*piid , IID_IRowsetInfo))
  2389.             pProp->dwPropertyID = DBPROP_IRowsetInfo;
  2390.         else if(InlineIsEqualGUID(*piid , IID_IRowsetLocate))
  2391.             pProp->dwPropertyID = DBPROP_IRowsetLocate;
  2392.         else if(InlineIsEqualGUID(*piid , IID_IColumnsRowset))
  2393.             pProp->dwPropertyID = DBPROP_IColumnsRowset;
  2394.         else if(InlineIsEqualGUID(*piid , IID_IRowsetResynch))
  2395.             pProp->dwPropertyID = DBPROP_IRowsetResynch;
  2396.         else if(InlineIsEqualGUID(*piid , IID_IRowsetScroll))
  2397.             pProp->dwPropertyID = DBPROP_IRowsetScroll;
  2398.         else if(InlineIsEqualGUID(*piid , IID_IRowsetChange))
  2399.             pProp->dwPropertyID = DBPROP_IRowsetChange;
  2400.         else if(InlineIsEqualGUID(*piid , IID_IRowsetUpdate))
  2401.             pProp->dwPropertyID = DBPROP_IRowsetUpdate;
  2402.         else if(InlineIsEqualGUID(*piid , IID_IRowsetIdentity))
  2403.             pProp->dwPropertyID = DBPROP_IRowsetIdentity;
  2404.         else if(InlineIsEqualGUID(*piid , IID_IConnectionPointContainer))
  2405.             pProp->dwPropertyID = DBPROP_IConnectionPointContainer;
  2406.         else if(InlineIsEqualGUID(*piid , IID_ISupportErrorInfo))
  2407.             pProp->dwPropertyID = DBPROP_ISupportErrorInfo;
  2408.         else if(InlineIsEqualGUID(*piid , IID_IRowsetIndex))
  2409.             pProp->dwPropertyID = DBPROP_IRowsetIndex;
  2410.     #if( OLEDBVER >= 0x0200 )
  2411.         else if(InlineIsEqualGUID(*piid , IID_IRowsetLockRows))
  2412.             pProp->dwPropertyID = DBPROP_IRowsetLockRows;
  2413.         else if(InlineIsEqualGUID(*piid , IID_IProvideMoniker))
  2414.             pProp->dwPropertyID = DBPROP_IProvideMoniker;
  2415.         else if(InlineIsEqualGUID(*piid , IID_IRowsetNotify))
  2416.             pProp->dwPropertyID = DBPROP_IRowsetNotify;
  2417.         else if(InlineIsEqualGUID(*piid , IID_IReadData))
  2418.             pProp->dwPropertyID = DBPROP_IReadData;
  2419.         else if(InlineIsEqualGUID(*piid , IID_IRowsetExactScroll))
  2420.             pProp->dwPropertyID = DBPROP_IRowsetExactScroll;
  2421.         else if(InlineIsEqualGUID(*piid , IID_IRowsetNextRowset))
  2422.             pProp->dwPropertyID = DBPROP_IRowsetNextRowset;
  2423.         else if(InlineIsEqualGUID(*piid , IID_IRowsetDelete))
  2424.             pProp->dwPropertyID = DBPROP_IRowsetDelete;
  2425.         else if(InlineIsEqualGUID(*piid , IID_IRowsetDeleteBookmarks))
  2426.             pProp->dwPropertyID = DBPROP_IRowsetDeleteBookmarks;
  2427.         else if(InlineIsEqualGUID(*piid , IID_IRowsetNewRow))
  2428.             pProp->dwPropertyID = DBPROP_IRowsetNewRow;
  2429.         else if(InlineIsEqualGUID(*piid , IID_IRowsetNewRowAfter))
  2430.             pProp->dwPropertyID = DBPROP_IRowsetNewRowAfter;
  2431.         else if(InlineIsEqualGUID(*piid , IID_IRowsetWithParameters))
  2432.             pProp->dwPropertyID = DBPROP_IRowsetWithParameters;
  2433.         else if(InlineIsEqualGUID(*piid , IID_IRowsetFind))
  2434.             pProp->dwPropertyID = DBPROP_IRowsetFind;
  2435.         else if(InlineIsEqualGUID(*piid , IID_IRowsetAsynch))
  2436.             pProp->dwPropertyID = DBPROP_IRowsetAsynch;
  2437.         else if(InlineIsEqualGUID(*piid , IID_IRowsetKeys))
  2438.             pProp->dwPropertyID = DBPROP_IRowsetKeys;
  2439.         else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchAll))
  2440.             pProp->dwPropertyID = DBPROP_IRowsetWatchAll;
  2441.         else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchNotify))
  2442.             pProp->dwPropertyID = DBPROP_IRowsetWatchNotify;
  2443.         else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchRegion))
  2444.             pProp->dwPropertyID = DBPROP_IRowsetWatchRegion;
  2445.         else if(InlineIsEqualGUID(*piid , IID_IRowsetCopyRows))
  2446.             pProp->dwPropertyID = DBPROP_IRowsetCopyRows;
  2447.     #endif //#if( OLEDBVER >= 0x0200 )
  2448.         else
  2449.             hr = S_FALSE;
  2450.  
  2451.         // If the IID can be mapped to a DBPROPID, the
  2452.         // we need to initialize the vValue to TRUE
  2453.         if(hr == S_OK)
  2454.         {
  2455.             // Set PropertySet
  2456.             pPropSet->guidPropertySet = DBPROPSET_ROWSET;
  2457.  
  2458.             // Set Property 
  2459.             pProp->dwOptions = DBPROPOPTIONS_REQUIRED;
  2460.             pProp->dwStatus = 0; 
  2461.             pProp->colid = DB_NULLID;
  2462.  
  2463.             VariantInit(&(pProp->vValue));
  2464.             pProp->vValue.vt = VT_BOOL;
  2465.             V_BOOL(&(pProp->vValue)) = VARIANT_TRUE;
  2466.         }
  2467.  
  2468.         return hr;
  2469.     }
  2470.  
  2471.     //Check the arguments for Retrieve Properties
  2472.     HRESULT    GetPropertiesArgChk(const ULONG cPropertySets, const DBPROPIDSET rgPropertySets[], 
  2473.                                 ULONG* pcProperties, DBPROPSET** prgProperties)
  2474.     {
  2475.         // Initialize values
  2476.         if(pcProperties)
  2477.             *pcProperties = 0;
  2478.         if(prgProperties)
  2479.             *prgProperties = NULL;    
  2480.  
  2481.         // Check Arguments
  2482.         if( ((cPropertySets > 0) && !rgPropertySets) || !pcProperties || !prgProperties )
  2483.             return E_INVALIDARG;
  2484.  
  2485.         // New argument check for > 1 cPropertyIDs and NULL pointer for 
  2486.         // array of property ids.
  2487.         for(ULONG ul=0; ul<cPropertySets; ul++)
  2488.         {
  2489.             if( rgPropertySets[ul].cPropertyIDs && !(rgPropertySets[ul].rgPropertyIDs) )
  2490.                 return E_INVALIDARG;
  2491.         
  2492.             // Check for propper formation of DBPROPSET_PROPERTIESINERROR
  2493.             if( (m_dwFlags & ARGCHK_PROPERTIESINERROR) && 
  2494.                 rgPropertySets[ul].guidPropertySet == DBPROPSET_PROPERTIESINERROR )
  2495.             {
  2496.                 if( (cPropertySets > 1) ||
  2497.                     (rgPropertySets[ul].cPropertyIDs != 0) ||
  2498.                     (rgPropertySets[ul].rgPropertyIDs != NULL) )
  2499.                     return E_INVALIDARG;
  2500.             }
  2501.         }
  2502.         
  2503.         return S_OK;
  2504.     }
  2505.     //Check the arguments for Set Properties
  2506.     static HRESULT SetPropertiesArgChk(const ULONG cPropertySets, const DBPROPSET rgPropertySets[])
  2507.     {
  2508.         if( cPropertySets > 0 && !rgPropertySets )
  2509.             return E_INVALIDARG;
  2510.  
  2511.         // New argument check for > 1 cPropertyIDs and NULL pointer for 
  2512.         // array of property ids.
  2513.         for(ULONG ul=0; ul<cPropertySets; ul++)
  2514.         {
  2515.             if( rgPropertySets[ul].cProperties && !(rgPropertySets[ul].rgProperties) )
  2516.                 return E_INVALIDARG;
  2517.         }
  2518.         
  2519.         return S_OK;
  2520.     }
  2521.     HRESULT    GetProperties(const ULONG cPropertySets, const DBPROPIDSET rgPropertySets[], 
  2522.                           ULONG* pcProperties, DBPROPSET** prgProperties, 
  2523.                           const ULONG cSelectProps = 1, const GUID** ppGuid = NULL)
  2524.     {
  2525.         UPROPVAL*        pUPropVal;
  2526.         ULONG            ulCurProp;
  2527.         ULONG            cTmpPropertySets = cPropertySets;
  2528.         HRESULT            hr = S_OK;
  2529.         ULONG            ulSet = 0;
  2530.         ULONG            ulNext = 0;
  2531.         ULONG            cSets = 0;
  2532.         ULONG            cProps = 0;
  2533.         ULONG            ulProp = 0;
  2534.         DWORD            dwStatus = 0;
  2535.         DBPROP*            pProp = NULL;
  2536.         DBPROP*            pCurProp = NULL;
  2537.         DBPROPSET*        pPropSet = NULL;
  2538.         UPROPINFO*        pUPropInfo = NULL;
  2539.         ULONG*            piSetIndex = NULL;
  2540.         ULONG*            piIndex = NULL;
  2541.         ULONG            ulCurSet = 0;
  2542.         ULONG            iPropSet;
  2543.  
  2544.         // ppGuid contains an array of GUIDs that the consumer can retrieve.
  2545.         // This is based upon the interface calling this function
  2546.         ATLASSERT(ppGuid != NULL);
  2547.  
  2548.         // We need to have special handling for DBPROPSET_PROPERTIESINERROR..
  2549.         // Turn on a flags to indicate this mode and make cTmpPropertySets
  2550.         // appear to be 0
  2551.         if( (m_dwFlags & ARGCHK_PROPERTIESINERROR) &&
  2552.             rgPropertySets && 
  2553.             (rgPropertySets[0].guidPropertySet == DBPROPSET_PROPERTIESINERROR) )
  2554.         {
  2555.             cTmpPropertySets = 0;
  2556.             dwStatus |= GETPROP_PROPSINERROR;
  2557.         }
  2558.  
  2559.         // If the consumer does not restrict the property sets
  2560.         // by specify an array of property sets and a cTmpPropertySets
  2561.         // greater than 0, then we need to make sure we 
  2562.         // have some to return
  2563.         if( cTmpPropertySets == 0 )
  2564.         {
  2565.             // There are times when we are called from IRowsetInfo, ISessionProperties, etc.
  2566.             // where we should return only the appropriate rowset when cTmpPropertySets is
  2567.             // zero.  This solves the problem if the user has more than one set specified in
  2568.             // their PROPSET_MAP.
  2569.  
  2570.             // Determine the number of property sets supported
  2571.             if (ppGuid == NULL)
  2572.             {
  2573.                 cSets = m_cUPropSet;
  2574.             }
  2575.             else
  2576.             {
  2577.                 ULONG ulActualProps = 0;
  2578.                 piSetIndex = new ULONG[cSelectProps];
  2579.  
  2580.                 // Also, find the index for the set we are looking for
  2581.                 for (ULONG l=0; l<cSelectProps; l++)
  2582.                 {
  2583.                     for (piSetIndex[l]=0; piSetIndex[l]<m_cUPropSet; piSetIndex[l]++)
  2584.                     {
  2585.                         if (InlineIsEqualGUID(*m_pUPropSet[piSetIndex[l]].pPropSet, *ppGuid[l]))
  2586.                         {
  2587.                             ulActualProps++;
  2588.                             break;
  2589.                         }
  2590.                     }
  2591.                 }
  2592.  
  2593.                 // YIKES!
  2594.                 cSets = ulActualProps;
  2595.                 ulActualProps = 0;
  2596.                 piIndex = new ULONG[cSets];
  2597.                 for (l=0; l<cSelectProps; l++)
  2598.                 {
  2599.                     if (piSetIndex[l] != m_cUPropSet) // this is an invalid index
  2600.                         piIndex[ulActualProps++] = piSetIndex[l];
  2601.                 }
  2602.  
  2603.                 delete piSetIndex;
  2604.                 piSetIndex = NULL;
  2605.  
  2606.             }
  2607.         }
  2608.         else
  2609.         {
  2610.             // Since special property set guids are not supported by
  2611.             // GetProperties, we can just use the count of property
  2612.             // sets given to us.
  2613.             cSets = cTmpPropertySets;
  2614.         }                            
  2615.  
  2616.         // If no properties set, then return
  2617.         if( cSets == 0 )
  2618.                 return S_OK;
  2619.                         
  2620.         // Allocate the DBPROPSET structures
  2621.         pPropSet = (DBPROPSET*)CoTaskMemAlloc(cSets * sizeof(DBPROPSET));
  2622.         if(pPropSet)
  2623.         {
  2624.             memset(pPropSet, 0, cSets * sizeof(DBPROPSET));
  2625.  
  2626.             // Fill in the output array
  2627.             iPropSet = 0;
  2628.             for(ulSet=0; ulSet<cSets; ulSet++)
  2629.             {
  2630.                 // Depending of if Property sets are specified store the
  2631.                 // return property set.
  2632.                 if( cTmpPropertySets == 0 )
  2633.                 {
  2634.                     ULONG lSet;
  2635.                 
  2636.                     if (ppGuid[ulSet] == NULL)
  2637.                         lSet = ulSet;
  2638.                     else
  2639.                         lSet = piIndex[ulSet];
  2640.                     if( m_pUPropSet[lSet].dwFlags & UPROPSET_HIDDEN )
  2641.                         continue;
  2642.                     
  2643.                     pPropSet[iPropSet].guidPropertySet = *(m_pUPropSet[lSet].pPropSet);
  2644.                 }
  2645.                 else
  2646.                     pPropSet[iPropSet].guidPropertySet = rgPropertySets[ulSet].guidPropertySet;         
  2647.  
  2648.                 iPropSet++;
  2649.             }
  2650.         }
  2651.         else
  2652.         {
  2653.             ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROPSET array for GetProperties\n");
  2654.             delete piIndex;
  2655.             piIndex = NULL;
  2656.             return E_OUTOFMEMORY;
  2657.         }
  2658.             
  2659.         // Process requested or derived Property sets
  2660.         iPropSet=0;
  2661.         for(ulSet=0; ulSet<cSets; ulSet++)
  2662.         {
  2663.             cProps    = 0;
  2664.             pProp    = NULL;
  2665.             ulNext    = 0;
  2666.             dwStatus &= (GETPROP_ERRORSOCCURRED | GETPROP_VALIDPROP | GETPROP_PROPSINERROR);
  2667.  
  2668.             // Calculate the number of property nodes needed for this
  2669.             // property set.
  2670.             if( cTmpPropertySets == 0 )
  2671.             {
  2672.                 ULONG lSet;
  2673.  
  2674.                 if (ppGuid[ulSet] == NULL)
  2675.                     lSet = ulSet;
  2676.                 else
  2677.                     lSet = piIndex[ulSet];
  2678.  
  2679.                 // If processing requesting all property sets, do not
  2680.                 // return the hidden sets.
  2681.                 if( m_pUPropSet[lSet].dwFlags & UPROPSET_HIDDEN )
  2682.                     continue;
  2683.  
  2684.                 cProps = m_pUPropSet[lSet].cUPropInfo;
  2685.  
  2686.                 // Add Enough space for node that are colid specific
  2687.                 cProps += GetCountofColids(&(m_pUProp[lSet]));
  2688.                 dwStatus |= GETPROP_ALLPROPIDS;
  2689.                 ulCurSet = lSet;
  2690.             }
  2691.             else
  2692.             {
  2693.                 ATLASSERT(ulSet == iPropSet);
  2694.  
  2695.                 // If the count of PROPIDs is 0 or It is a special property set, then 
  2696.                 // the consumer is requesting all propids for this property set.
  2697.                 if(rgPropertySets[ulSet].cPropertyIDs == 0)
  2698.                 {
  2699.                     dwStatus |= GETPROP_ALLPROPIDS;
  2700.                     // We have to determine if the property set is supported and if so
  2701.                     // the count of properties in the set.
  2702.                     BOOL bAvailable = false;
  2703.                     for (ULONG l=0; l<cSelectProps; l++)
  2704.                     {
  2705.                         if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
  2706.                             bAvailable |= true;
  2707.                     }
  2708.  
  2709.                     if (bAvailable && 
  2710.                             GetIndexofPropSet(&(pPropSet[iPropSet].guidPropertySet), &ulCurSet) == S_OK)
  2711.                     {
  2712.                         cProps += m_pUPropSet[ulCurSet].cUPropInfo;
  2713.                         // Add Enough space for node that are colid specific
  2714.                         cProps += GetCountofColids(&m_pUProp[ulCurSet]);
  2715.                     }
  2716.                     else
  2717.                     {
  2718.                         // Not Supported                    
  2719.                         dwStatus |= GETPROP_ERRORSOCCURRED;
  2720.                         goto NEXT_SET;
  2721.                     
  2722.                     }
  2723.                 }
  2724.                 else
  2725.                 {
  2726.                     cProps = rgPropertySets[ulSet].cPropertyIDs;
  2727.                     // Check to see if this is a supported interface based on ppGuid.
  2728.                     BOOL bAvailable = false;
  2729.                     for (ULONG l=0; l<cSelectProps; l++)
  2730.                     {
  2731.                         if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
  2732.                             bAvailable |= true;
  2733.                     }
  2734.  
  2735.                     if (!bAvailable || 
  2736.                         (GetIndexofPropSet(&(pPropSet[iPropSet].guidPropertySet), &ulCurSet) != S_OK))
  2737.                     {
  2738.                         dwStatus |= GETPROP_NOTSUPPORTED;
  2739.                         dwStatus |= GETPROP_ERRORSOCCURRED;
  2740.                     }
  2741.                 }
  2742.             }
  2743.  
  2744.  
  2745.             // Allocate DBPROP array
  2746.             if( cProps == 0 )            //Possible with Hidden Passthrough sets
  2747.                 goto NEXT_SET;
  2748.  
  2749.             pProp = (DBPROP*)CoTaskMemAlloc(cProps * sizeof(DBPROP));
  2750.             if( pProp )
  2751.             {
  2752.                 // Initialize Buffer
  2753.                 memset(pProp, 0, cProps * sizeof(DBPROP));
  2754.                 for(ulProp=0; ulProp<cProps; ulProp++)
  2755.                 {
  2756.                     VariantInit(&(pProp[ulProp].vValue));
  2757.                     if( dwStatus & GETPROP_NOTSUPPORTED )
  2758.                     {
  2759.                         // Not supported, thus we need to mark all as NOT_SUPPORTED
  2760.                         pProp[ulProp].dwPropertyID    = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  2761.                         pProp[ulProp].dwStatus        = DBPROPSTATUS_NOTSUPPORTED;
  2762.                     }                    
  2763.                 }
  2764.                 // Make sure we support the property set
  2765.                 if( dwStatus & GETPROP_NOTSUPPORTED )
  2766.                 {
  2767.                     ulNext = cProps;
  2768.                     goto NEXT_SET;
  2769.                 }
  2770.  
  2771.                 // Now that we have determined we can support the property set, we
  2772.                 // need to gather current property values
  2773.                 for(ulProp=0; ulProp<cProps; ulProp++)
  2774.                 {
  2775.                     pCurProp = &(pProp[ulNext]);
  2776.  
  2777.                     //Initialize Variant Value
  2778.                     pCurProp->dwStatus = DBPROPSTATUS_OK;
  2779.  
  2780.                     // Retrieve current value of properties
  2781.                     if( dwStatus & GETPROP_ALLPROPIDS )
  2782.                     {
  2783.                         // Verify property is supported, if not do not return 
  2784.                         if( !TESTBIT(&(m_rgdwSupported[ulCurSet * m_cElemPerSupported]), ulProp) )
  2785.                             continue;
  2786.  
  2787.                         // If we are looking for properties in error, then we should ignore all
  2788.                         // that are not in error.
  2789.                         if( (dwStatus & GETPROP_PROPSINERROR) &&
  2790.                             !TESTBIT(&(m_rgdwPropsInError[ulCurSet * m_cElemPerSupported]), ulProp) )
  2791.                             continue;
  2792.  
  2793.                         pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulProp]);
  2794.  
  2795.                         ATLASSERT( pUPropInfo );
  2796.  
  2797.                         pCurProp->dwPropertyID = pUPropInfo->dwPropId;
  2798.                         pCurProp->colid = DB_NULLID;
  2799.  
  2800.                         // If the property is WRITEABLE or CHANGABLE, then the value will
  2801.                         // be gotten from the UPROPVAL array, else it will be
  2802.                         // derive from the GetDefaultValue
  2803.                         if( pUPropInfo->dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2804.                         {
  2805.                             pUPropVal = &(m_pUProp[ulCurSet].
  2806.                                 pUPropVal[GetUPropValIndex(ulCurSet, pCurProp->dwPropertyID)]);
  2807.                             ATLASSERT( pUPropVal );
  2808.  
  2809.                             // Check to see if this property supports column level,
  2810.                             // if so, dump those nodes
  2811.                             if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  2812.                             {
  2813.                                 if( pUPropVal->pCColumnIds )
  2814.                                 {
  2815.                                     RetrieveColumnIdProps(pProp, pUPropVal, &ulNext);
  2816.                                     continue;
  2817.                                 }
  2818.                             }
  2819.  
  2820.                             pCurProp->dwOptions = pUPropVal->dwOption;
  2821.                             hr = VariantCopy(&(pCurProp->vValue), &(pUPropVal->vValue));
  2822.                         }
  2823.                         else
  2824.                         {
  2825.                             GetDefaultValue(ulCurSet, pUPropInfo->dwPropId, 
  2826.                                 &(pCurProp->dwOptions), &(pCurProp->vValue));
  2827.                         }
  2828.         
  2829.                         // Return all Properties in Error with CONFLICT status
  2830.                         if( dwStatus & GETPROP_PROPSINERROR )
  2831.                             pCurProp->dwStatus = DBPROPSTATUS_CONFLICTING;
  2832.                         
  2833.                         dwStatus |= GETPROP_VALIDPROP;
  2834.                     }
  2835.                     else
  2836.                     {
  2837.                         // Process Properties based on Restriction array.
  2838.  
  2839.                         pCurProp->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
  2840.                         pCurProp->colid = DB_NULLID;
  2841.  
  2842.                         if( GetIndexofPropIdinPropSet(ulCurSet, pCurProp->dwPropertyID, 
  2843.                             &ulCurProp) == S_OK)
  2844.                         {
  2845.                             // Supported
  2846.                             pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]);
  2847.                             ATLASSERT( pUPropInfo );
  2848.  
  2849.                             // If the property is WRITEABLE, then the value will
  2850.                             // be gotten from the UPROPVAL array, else it will be
  2851.                             // derive from the GetDefaultValue
  2852.                             if( pUPropInfo->dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  2853.                             {
  2854.                                 pUPropVal = &(m_pUProp[ulCurSet].
  2855.                                     pUPropVal[GetUPropValIndex(ulCurSet, pCurProp->dwPropertyID)]);
  2856.                                 ATLASSERT( pUPropVal );
  2857.                             
  2858.                                 // Check to see if this property supports column level,
  2859.                                 // if so, dump those nodes
  2860.                                 if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  2861.                                 {
  2862.                                     if( pUPropVal->pCColumnIds )
  2863.                                     {
  2864.                                         RetrieveColumnIdProps(pProp, pUPropVal, &ulNext);
  2865.                                         continue;
  2866.                                     }
  2867.                                 }
  2868.                                 pCurProp->dwOptions = pUPropVal->dwOption;
  2869.                                 hr = VariantCopy(&(pCurProp->vValue), &(pUPropVal->vValue));
  2870.                             }
  2871.                             else
  2872.                             {
  2873.                                 GetDefaultValue(ulCurSet, pUPropInfo->dwPropId, 
  2874.                                     &(pCurProp->dwOptions), &(pCurProp->vValue));
  2875.  
  2876.                             }
  2877.  
  2878.                             dwStatus |= GETPROP_VALIDPROP;
  2879.                         }
  2880.                         else
  2881.                         {
  2882.                             // Not Supported
  2883.                             pCurProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  2884.                             dwStatus |= GETPROP_ERRORSOCCURRED;
  2885.                         }
  2886.                     }
  2887.  
  2888.                     // Increment return nodes count
  2889.                     ulNext++;
  2890.                 }
  2891.             }
  2892.             else
  2893.             {
  2894.                 ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROP array for GetProperties\n");
  2895.                 if( pPropSet )
  2896.                 {
  2897.                     // Free any DBPROP arrays 
  2898.                     for(ulSet=0; ulSet<cSets; ulSet++)
  2899.                     {
  2900.                         // Need to loop through all the VARIANTS and clear them
  2901.                         for(ulProp=0; ulProp<pPropSet[ulSet].cProperties; ulProp++)
  2902.                             VariantClear(&(pPropSet[ulSet].rgProperties[ulProp].vValue));
  2903.                         if( pPropSet[ulSet].rgProperties )
  2904.                             CoTaskMemFree(pPropSet[ulSet].rgProperties);
  2905.                     }
  2906.  
  2907.                     // Free DBPROPSET
  2908.                     CoTaskMemFree(pPropSet);
  2909.                 }
  2910.                 //Since we have no properties to return, then we
  2911.                 //need to free allocated memory and return 0,NULL
  2912.                 if(pPropSet)
  2913.                 {
  2914.                     // Free any DBPROP arrays 
  2915.                     for(ulSet=0; ulSet<cSets; ulSet++)
  2916.                     {
  2917.                         // Need to loop through all the VARIANTS and clear them
  2918.                         for(ulProp=0; ulProp<pPropSet[ulSet].cProperties; ulProp++)
  2919.                             VariantClear(&(pPropSet[ulSet].rgProperties[ulProp].vValue));
  2920.                         if( pPropSet[ulSet].rgProperties )
  2921.                             CoTaskMemFree(pPropSet[ulSet].rgProperties);
  2922.                     }
  2923.  
  2924.                     // Free DBPROPSET
  2925.                     CoTaskMemFree(pPropSet);
  2926.                 }
  2927.                 *pcProperties = 0;
  2928.                 *prgProperties = NULL;
  2929.                 delete piIndex;
  2930.                 piIndex = NULL;
  2931.                 return E_OUTOFMEMORY;
  2932.             }
  2933.  
  2934. NEXT_SET:
  2935.             // It is possible that all properties are not supported,
  2936.             // thus we should delete that memory and set rgProperties
  2937.             // to NULL
  2938.             if( ulNext == 0 && pProp )
  2939.             {
  2940.                 CoTaskMemFree(pProp);
  2941.                 pProp = NULL;
  2942.             }
  2943.  
  2944.             pPropSet[iPropSet].cProperties = ulNext;
  2945.             pPropSet[iPropSet].rgProperties = pProp;
  2946.             iPropSet++;
  2947.         }
  2948.  
  2949.         *pcProperties = iPropSet;
  2950.         *prgProperties = pPropSet;
  2951.         
  2952.         delete piIndex;
  2953.         piIndex = NULL;
  2954.  
  2955.         // At least one propid was marked as not S_OK
  2956.         if( dwStatus & GETPROP_ERRORSOCCURRED )
  2957.         {
  2958.             // If at least 1 property was set
  2959.             if( dwStatus & GETPROP_VALIDPROP )
  2960.                 return DB_S_ERRORSOCCURRED;
  2961.             else
  2962.             {
  2963.                 // Do not free any of the memory on a DB_E_
  2964.                 return DB_E_ERRORSOCCURRED;
  2965.             }
  2966.         }
  2967.  
  2968.         return S_OK;
  2969.     }
  2970.     HRESULT    SetProperties(const DWORD /*dwStatus*/, const ULONG cPropertySets, 
  2971.             const DBPROPSET rgPropertySets[], const ULONG cSelectProps = 1, 
  2972.             const GUID** ppGuid = NULL, bool bIsCreating = false)
  2973.     {
  2974.         DWORD dwState = 0;
  2975.         ULONG ulCurSet, ulCurProp, ulProp;
  2976.         DBPROP*    rgDBProp;
  2977.         UPROPINFO* pUPropInfo;
  2978.         VARIANT    vDefaultValue;
  2979.         DWORD dwOption;
  2980.  
  2981.         // ppGuid specifies the property sets that the consumer can set based
  2982.         // on the interface that called this function.
  2983.         ATLASSERT(ppGuid != NULL);
  2984.  
  2985.         if ((cPropertySets != 0) && (rgPropertySets == NULL))
  2986.             return E_INVALIDARG;
  2987.  
  2988.         // Initialize Variant
  2989.         VariantInit(&vDefaultValue);
  2990.  
  2991.         // Process property sets
  2992.         for(ULONG ulSet=0; ulSet<cPropertySets; ulSet++)
  2993.         {
  2994.             if ((rgPropertySets[ulSet].cProperties != 0) && (rgPropertySets[ulSet].rgProperties == NULL))
  2995.                 return E_INVALIDARG;
  2996.  
  2997.             bool bAvailable = false;
  2998.             for (ULONG l=0; l<cSelectProps; l++)
  2999.             {
  3000.                 if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
  3001.                     bAvailable |= true;
  3002.             }
  3003.  
  3004.             // Make sure we support the property set
  3005.             if( !bAvailable || 
  3006.                 (GetIndexofPropSet(&(rgPropertySets[ulSet].guidPropertySet), &ulCurSet) == S_FALSE ))
  3007.             {
  3008.                 // Not supported, thus we need to mark all as NOT_SUPPORTED
  3009.                 rgDBProp = rgPropertySets[ulSet].rgProperties;
  3010.                 for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++)
  3011.                 {
  3012.                     dwState |= SETPROP_ERRORS;
  3013.                     dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  3014.                     rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  3015.                 }
  3016.                 continue;
  3017.             }
  3018.  
  3019.             // Handle property sets marked as pass through
  3020.             if( m_pUPropSet[ulCurSet].dwFlags & UPROPSET_PASSTHROUGH )
  3021.             {
  3022.                 HRESULT hr = SetPassThrough(&rgPropertySets[ulSet]);
  3023.                 if( hr == DB_E_ERRORSOCCURRED )
  3024.                 {
  3025.                     dwState |= SETPROP_ERRORS;
  3026.                     dwState |= SETPROP_WAS_REQUIRED;
  3027.                 }
  3028.                 else if( hr == DB_S_ERRORSOCCURRED )
  3029.                 {
  3030.                     dwState |= SETPROP_ERRORS;    
  3031.                     dwState |= SETPROP_VALIDPROP; 
  3032.                 }
  3033.                 else
  3034.                 {
  3035.                     ATLASSERT( hr == S_OK );
  3036.                     dwState |= SETPROP_VALIDPROP; 
  3037.                 }
  3038.                     
  3039.                 continue;
  3040.             }        
  3041.             
  3042.             // Handle properties of a supported property set
  3043.             rgDBProp = rgPropertySets[ulSet].rgProperties;
  3044.             for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++)
  3045.             {
  3046.                 // Is this a supported PROPID for this property set
  3047.                 if( GetIndexofPropIdinPropSet(ulCurSet, rgDBProp[ulProp].dwPropertyID, 
  3048.                     &ulCurProp) == S_FALSE)
  3049.                 {
  3050.                     dwState |= SETPROP_ERRORS;
  3051.                     dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  3052.                     rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  3053.                     continue;
  3054.                 }
  3055.  
  3056.                 // Set the pUPropInfo pointer
  3057.                 pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]); 
  3058.                 ATLASSERT( pUPropInfo );
  3059.  
  3060.                 // check dwOption for a valid option
  3061.                 if( (rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_REQUIRED)  &&
  3062.                     (rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_SETIFCHEAP) )
  3063.                 {
  3064.                     ATLTRACE2(atlTraceDBProvider, 0, "SetProperties dwOptions Invalid: %u\n", rgDBProp[ulProp].dwOptions);
  3065.                     dwState |= SETPROP_ERRORS;
  3066.                     dwState |= SETPROP_WAS_REQUIRED;
  3067.                     rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADOPTION;
  3068.                     continue;
  3069.                 }
  3070.  
  3071.                 // Check that the property is settable
  3072.                 // We do not check against DBPROPFLAGS_CHANGE here
  3073.                 if( (pUPropInfo->dwFlags & DBPROPFLAGS_WRITE) == 0 )
  3074.                 {
  3075.                     rgDBProp[ulProp].dwStatus = DBPROPSTATUS_OK;
  3076.  
  3077.                     VariantClear(&vDefaultValue);
  3078.  
  3079.                     // VT_EMPTY against a read only property should be a no-op since
  3080.                     // the VT_EMPTY means the default.
  3081.                     if( V_VT(&rgDBProp[ulProp].vValue) == VT_EMPTY )
  3082.                     {
  3083.                         dwState |= SETPROP_VALIDPROP;
  3084.                         continue;
  3085.                     }
  3086.  
  3087.                     if( SUCCEEDED(GetDefaultValue(ulCurSet, rgDBProp[ulProp].dwPropertyID, 
  3088.                             &dwOption, &(vDefaultValue))) )
  3089.                     {
  3090.                         if( V_VT(&rgDBProp[ulProp].vValue) ==  V_VT(&vDefaultValue) )
  3091.                         {
  3092.                             switch( V_VT(&vDefaultValue) )
  3093.                             {
  3094.                                 case VT_BOOL:
  3095.                                     if( V_BOOL(&rgDBProp[ulProp].vValue) == V_BOOL(&vDefaultValue) )
  3096.                                     {
  3097.                                         dwState |= SETPROP_VALIDPROP;
  3098.                                         continue;
  3099.                                     }
  3100.                                     break;
  3101.                                 case VT_I2:
  3102.                                     if( V_I2(&rgDBProp[ulProp].vValue) == V_I2(&vDefaultValue) )
  3103.                                     {
  3104.                                         dwState |= SETPROP_VALIDPROP;
  3105.                                         continue;
  3106.                                     }
  3107.                                     break;
  3108.                                 case VT_I4:
  3109.                                     if( V_I4(&rgDBProp[ulProp].vValue) == V_I4(&vDefaultValue) )
  3110.                                     {
  3111.                                         dwState |= SETPROP_VALIDPROP;
  3112.                                         continue;
  3113.                                     }
  3114.                                     break;
  3115.                                 case VT_BSTR:
  3116.                                     if( wcscmp(V_BSTR(&rgDBProp[ulProp].vValue), V_BSTR(&vDefaultValue)) == 0 )
  3117.                                     {
  3118.                                         dwState |= SETPROP_VALIDPROP;
  3119.                                         continue;
  3120.                                     }
  3121.                                     break;
  3122.                             }
  3123.                         }
  3124.                     }
  3125.  
  3126.                     dwState |= SETPROP_ERRORS;
  3127.                     dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  3128.                     rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSETTABLE;
  3129.                     continue;
  3130.                 }
  3131.  
  3132.                 // Check that the property is being set with the correct VARTYPE
  3133.                 if( (rgDBProp[ulProp].vValue.vt != pUPropInfo->VarType) && 
  3134.                     (rgDBProp[ulProp].vValue.vt != VT_EMPTY) )
  3135.                 {
  3136.                     dwState |= SETPROP_ERRORS;
  3137.                     dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  3138.                     rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE;
  3139.                     continue;
  3140.                 }
  3141.  
  3142.                 // Check that the value is legal
  3143.                 if( (rgDBProp[ulProp].vValue.vt != VT_EMPTY) && 
  3144.                     IsValidValue(ulCurSet, &(rgDBProp[ulProp])) == S_FALSE )
  3145.                 {
  3146.                     dwState |= SETPROP_ERRORS;
  3147.                     dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  3148.                     rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE;
  3149.                     continue;
  3150.                 }
  3151.  
  3152.  
  3153.                 // Check for a bad COLID, we only catch bad DBIDs
  3154.                 if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
  3155.                 {
  3156.                     if( CDBIDOps::IsValidDBID(&(rgDBProp[ulProp].colid)) == S_FALSE )
  3157.                     {
  3158.                         dwState |= SETPROP_ERRORS;
  3159.                         dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
  3160.                         rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADCOLUMN;
  3161.                         continue;
  3162.                     }
  3163.                     dwState |= SETPROP_COLUMN_LEVEL;
  3164.  
  3165.                 }
  3166.  
  3167.                 if( SUCCEEDED(SetProperty(ulCurSet, ulCurProp, /*pUPropInfo,*/ &(rgDBProp[ulProp]))) )
  3168.                 {
  3169.                     dwState |= SETPROP_VALIDPROP;
  3170.                 }
  3171.             }
  3172.         }
  3173.  
  3174.         VariantClear(&vDefaultValue);
  3175.  
  3176.         // At least one propid was marked as not S_OK
  3177.         if( dwState & SETPROP_ERRORS )
  3178.         {
  3179.             if (!bIsCreating)
  3180.             {
  3181.                 return (dwState & SETPROP_VALIDPROP) ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED;
  3182.             }
  3183.             else
  3184.             {
  3185.                 return (dwState & SETPROP_WAS_REQUIRED) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED;
  3186.             }
  3187.         }
  3188.                         
  3189.         return S_OK;
  3190.     }
  3191.  
  3192.     void SetPropertyInError(const ULONG iPropSet, const ULONG iPropId)
  3193.     {
  3194.         SETBIT(&(m_rgdwPropsInError[iPropSet * m_cElemPerSupported]), iPropId);
  3195.     }
  3196.     void ClearPropertyInError()
  3197.     {
  3198.         ATLASSERT( m_rgdwPropsInError );
  3199.         memset(m_rgdwPropsInError, 0, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD)); 
  3200.     }
  3201.  
  3202.     BOOL IsPropSet(const GUID* pguidPropSet, DBPROPID dwPropId)
  3203.     {
  3204.         HRESULT        hr;
  3205.         ULONG        iPropSet;
  3206.         ULONG        iPropId;
  3207.         VARIANT        vValue;
  3208.         DWORD        dwOptions;
  3209.  
  3210.         VariantInit(&vValue);
  3211.  
  3212.         if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
  3213.         {
  3214.             if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
  3215.             {        
  3216.                 if( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & 
  3217.                     (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  3218.                 {
  3219.                     ULONG iPropVal = GetUPropValIndex(iPropSet, dwPropId);
  3220.                     
  3221.                     dwOptions = m_pUProp[iPropSet].pUPropVal[iPropVal].dwOption;
  3222.                     hr = VariantCopy(&vValue, &(m_pUProp[iPropSet].
  3223.                         pUPropVal[iPropVal].vValue));
  3224.                 }
  3225.                 else
  3226.                 {
  3227.                     hr = GetDefaultValue(iPropSet, dwPropId, 
  3228.                         &dwOptions, &vValue);
  3229.                 }
  3230.  
  3231.                 if( dwOptions == DBPROPOPTIONS_REQUIRED )
  3232.                 {
  3233.                     ATLASSERT( vValue.vt == VT_BOOL );
  3234.                     if( SUCCEEDED(hr) && 
  3235.                         (V_BOOL(&vValue) == VARIANT_TRUE) )
  3236.                     {
  3237.                         VariantClear(&vValue);
  3238.                         return TRUE;
  3239.                     }
  3240.                 }
  3241.             }
  3242.         }
  3243.  
  3244.         VariantClear(&vValue);
  3245.         return FALSE;
  3246.     }
  3247.     HRESULT    GetPropValue(const GUID* pguidPropSet, DBPROPID dwPropId, VARIANT* pvValue)
  3248.     {
  3249.         HRESULT        hr = E_FAIL;
  3250.         ULONG        iPropSet;
  3251.         ULONG        iPropId;
  3252.         DWORD        dwOptions;
  3253.  
  3254.         if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
  3255.         {
  3256.             if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
  3257.             {        
  3258.                 if( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
  3259.                 {
  3260.                     hr = VariantCopy(pvValue, &(m_pUProp[iPropSet].pUPropVal[
  3261.                         GetUPropValIndex(iPropSet, dwPropId)].vValue));
  3262.                 }
  3263.                 else
  3264.                 {
  3265.                     VariantClear(pvValue);
  3266.  
  3267.                     hr = GetDefaultValue(iPropSet, dwPropId, 
  3268.                         &dwOptions, pvValue);
  3269.                 }
  3270.             }
  3271.         }
  3272.  
  3273.         return hr;
  3274.     }
  3275.     HRESULT    SetPropValue(const GUID* pguidPropSet,DBPROPID dwPropId, VARIANT* pvValue)
  3276.     {
  3277.         HRESULT        hr = E_FAIL;
  3278.         ULONG        iPropSet;
  3279.         ULONG        iPropId;
  3280.  
  3281.         if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
  3282.         {
  3283.             if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
  3284.             {        
  3285.                 ATLASSERT( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) );
  3286.  
  3287.                 hr = VariantCopy(&(m_pUProp[iPropSet].pUPropVal[
  3288.                         GetUPropValIndex(iPropSet, dwPropId)].vValue), pvValue);
  3289.             }
  3290.         }
  3291.  
  3292.         return hr;
  3293.     }
  3294.  
  3295.     HRESULT    CopyUPropVal(ULONG iPropSet, UPROPVAL* rgUPropVal)
  3296.     {
  3297.         HRESULT    hr = S_OK;
  3298.         UPROP* pUProp;
  3299.         UPROPVAL* pUPropVal;
  3300.         DBPROP dbProp;
  3301.  
  3302.         ATLASSERT(rgUPropVal);
  3303.         ATLASSERT(iPropSet < m_cUPropSet);
  3304.         
  3305.         VariantInit(&dbProp.vValue);
  3306.  
  3307.         pUProp = &(m_pUProp[iPropSet]);
  3308.         for(ULONG ul=0; ul<pUProp->cPropIds; ul++)
  3309.         {
  3310.             pUPropVal = &(pUProp->pUPropVal[ul]);
  3311.  
  3312.             // Transfer dwOptions
  3313.             rgUPropVal[ul].dwOption = pUPropVal->dwOption;
  3314.  
  3315.             // Transfer Flags
  3316.             rgUPropVal[ul].dwFlags = pUPropVal->dwFlags;
  3317.  
  3318.             // Transfer Column Properties
  3319.             if( pUPropVal->pCColumnIds )
  3320.             {
  3321.                 ATLTRY(rgUPropVal[ul].pCColumnIds = new CColumnIds)
  3322.                 if( rgUPropVal[ul].pCColumnIds )
  3323.                 {
  3324.                     CColumnIds* pColIds = pUPropVal->pCColumnIds;
  3325.                     for (int i = 0; i < pColIds->GetSize(); i++)
  3326.                     {
  3327.                         hr = (pUPropVal->pCColumnIds)->GetValue(i, &(dbProp.dwOptions),&(dbProp.colid), &(dbProp.vValue));
  3328.                         if( FAILED(hr) )
  3329.                             goto EXIT;                                                
  3330.                         if( FAILED(hr = (rgUPropVal[ul].pCColumnIds)->AddColumnId(&dbProp)) )
  3331.                             goto EXIT;
  3332.                     }
  3333.                 }
  3334.                 else
  3335.                 {
  3336.                     hr = E_OUTOFMEMORY;
  3337.                     goto EXIT;        
  3338.                 }
  3339.             }
  3340.             else
  3341.             {
  3342.                 rgUPropVal[ul].pCColumnIds = NULL;
  3343.             }
  3344.  
  3345.             // Transfer value
  3346.             VariantInit(&(rgUPropVal[ul].vValue));
  3347.             if( FAILED(hr = VariantCopy(&(rgUPropVal[ul].vValue), 
  3348.                 &(pUPropVal->vValue))) )
  3349.                 goto EXIT;
  3350.         }
  3351.  
  3352. EXIT:    
  3353.         VariantClear(&(dbProp.vValue));
  3354.         return hr;
  3355.     }
  3356.  
  3357.     //Pointer to properties in error mask
  3358.     DWORD* GetPropsInErrorPtr(){return m_rgdwPropsInError;}
  3359.     ULONG GetUPropSetCount() {return m_cUPropSet;}
  3360.     void SetUPropSetCount(ULONG c) {m_cUPropSet = c;}
  3361.  
  3362.     // NOTE: The following functions depend on all prior
  3363.     // properties in the array being writable.
  3364.     // This is because the UPROP array contains only writable elements,
  3365.     // and the UPROPINFO array contains writable and read-only elements.
  3366.     // (If this is a problem, we would need to define which one it came from
  3367.     // and add the appropriate ATLASSERTs...)
  3368.  
  3369.     //Get DBPROPOPTIONS_xx
  3370.     DWORD GetPropOption(ULONG iPropSet, ULONG iProp)
  3371.     {
  3372.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3373.         return m_pUProp[iPropSet].pUPropVal[iProp].dwOption;
  3374.     }
  3375.     //Set DBPROPOPTIONS_xx
  3376.     void SetPropOption(ULONG iPropSet, ULONG iProp, DWORD dwOption)
  3377.     {
  3378.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3379.         m_pUProp[iPropSet].pUPropVal[iProp].dwOption = dwOption;
  3380.     }
  3381.     //Determine if property is required and variant_true
  3382.     BOOL IsRequiredTrue(ULONG iPropSet, ULONG iProp)
  3383.     {
  3384.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3385.         ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BOOL);
  3386.         ATLASSERT(V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_TRUE
  3387.         ||     V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_FALSE);
  3388.  
  3389.         return( (m_pUProp[iPropSet].pUPropVal[iProp].dwOption == DBPROPOPTIONS_REQUIRED) &&
  3390.                 (V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_TRUE) );
  3391.     }
  3392.     DWORD GetInternalFlags(ULONG iPropSet, ULONG iProp)
  3393.     {
  3394.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3395.         return m_pUProp[iPropSet].pUPropVal[iProp].dwFlags;
  3396.     }
  3397.     void AddInternalFlags(ULONG iPropSet, ULONG iProp, DWORD dwFlags)
  3398.     {
  3399.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3400.         m_pUProp[iPropSet].pUPropVal[iProp].dwFlags |= dwFlags;
  3401.     }
  3402.     void RemoveInternalFlags(ULONG iPropSet, ULONG iProp, DWORD dwFlags)
  3403.     {
  3404.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3405.         m_pUProp[iPropSet].pUPropVal[iProp].dwFlags &= ~dwFlags;
  3406.     }
  3407.     VARIANT * GetVariant(ULONG iPropSet, ULONG iProp)
  3408.     {
  3409.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3410.         return & m_pUProp[iPropSet].pUPropVal[iProp].vValue;
  3411.     }
  3412.     HRESULT SetVariant(ULONG iPropSet, ULONG iProp, VARIANT *pv )
  3413.     {
  3414.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3415.         // Does VariantClear first.
  3416.         return VariantCopy( &m_pUProp[iPropSet].pUPropVal[iProp].vValue, pv );
  3417.     }
  3418.     void SetValEmpty(ULONG iPropSet, ULONG iProp)
  3419.     {
  3420.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3421.         VariantClear( &m_pUProp[iPropSet].pUPropVal[iProp].vValue );
  3422.     }
  3423.     BOOL IsEmpty(ULONG iPropSet, ULONG iProp)
  3424.     {
  3425.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3426.         return ( m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_EMPTY);
  3427.     }
  3428.     void SetValBool(ULONG iPropSet, ULONG iProp, VARIANT_BOOL bVal)
  3429.     {
  3430.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3431.         // Note that we accept any "true" value.
  3432.         VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3433.         m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_BOOL;
  3434.         V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) = (bVal ? VARIANT_TRUE : VARIANT_FALSE);
  3435.     }
  3436.     VARIANT_BOOL GetValBool(ULONG iPropSet, ULONG iProp)
  3437.     {
  3438.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3439.         ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BOOL);
  3440.         return V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3441.     }
  3442.     void SetValShort(ULONG iPropSet, ULONG iProp, SHORT iVal )
  3443.     {
  3444.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3445.         VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3446.         m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_I2;
  3447.         m_pUProp[iPropSet].pUPropVal[iProp].vValue.iVal = iVal;
  3448.     }
  3449.     SHORT GetValShort(ULONG iPropSet, ULONG iProp)
  3450.     {
  3451.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3452.         ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_I2);
  3453.         return m_pUProp[iPropSet].pUPropVal[iProp].vValue.iVal;
  3454.     }
  3455.     void SetValLong(ULONG iPropSet, ULONG iProp, LONG lVal)
  3456.     {
  3457.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3458.         VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
  3459.         m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_I4;
  3460.         m_pUProp[iPropSet].pUPropVal[iProp].vValue.lVal = lVal;
  3461.     }
  3462.     LONG GetValLong(ULONG iPropSet, ULONG iProp)
  3463.     {
  3464.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3465.         ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_I4);
  3466.         return m_pUProp[iPropSet].pUPropVal[iProp].vValue.lVal;
  3467.     }
  3468.     HRESULT SetValString(ULONG iPropSet, ULONG iProp, const WCHAR *pwsz)
  3469.     {
  3470.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3471.         VARIANT *pv = &m_pUProp[iPropSet].pUPropVal[iProp].vValue;
  3472.         VariantClear(pv);
  3473.         pv->bstrVal = SysAllocString(pwsz);
  3474.         if (pv->bstrVal)
  3475.             pv->vt = VT_BSTR;
  3476.         else
  3477.             return E_FAIL;
  3478.  
  3479.         // See if this was used for non-string type.
  3480.         // Typically this is an easy way to pass integer as a string.
  3481.         if (GetExpectedVarType(iPropSet,iProp) == VT_BSTR)
  3482.             return NOERROR;
  3483.         if (pwsz[0] != L'\0')
  3484.             return VariantChangeType( pv, pv, 0, GetExpectedVarType(iPropSet,iProp) );
  3485.  
  3486.         // Set to "", which for non-string means empty.
  3487.         SysFreeString(pv->bstrVal);
  3488.         pv->vt = VT_EMPTY;
  3489.         return NOERROR;
  3490.     }
  3491.     const WCHAR * GetValString(ULONG iPropSet, ULONG iProp)
  3492.     {
  3493.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3494.         ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BSTR);
  3495.         return m_pUProp[iPropSet].pUPropVal[iProp].vValue.bstrVal;
  3496.     }
  3497.     const GUID * GetGuid(ULONG iPropSet)
  3498.     {
  3499.         ATLASSERT(iPropSet < m_cUPropSet);
  3500.         return m_pUPropSet[iPropSet].pPropSet;
  3501.     }
  3502.     DWORD GetPropID(ULONG iPropSet, ULONG iProp)
  3503.     {
  3504.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3505.         return m_pUPropSet[iPropSet].pUPropInfo[iProp].dwPropId;
  3506.     }
  3507.     VARTYPE GetExpectedVarType(ULONG iPropSet, ULONG iProp)
  3508.     {
  3509.         ATLASSERT((  (iPropSet < m_cUPropSet)    && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
  3510.         return m_pUPropSet[iPropSet].pUPropInfo[iProp].VarType;
  3511.     }
  3512.     virtual HRESULT    GetIndexofPropSet(const GUID* pPropSet, ULONG* pulCurSet)
  3513.     {
  3514.         ATLASSERT(pPropSet && pulCurSet);
  3515.  
  3516.         for(ULONG ul=0; ul<m_cUPropSet; ul++)
  3517.         {
  3518.             if( *pPropSet == *(m_pUPropSet[ul].pPropSet) )
  3519.             {
  3520.                 *pulCurSet = ul;
  3521.                 return S_OK;
  3522.             }
  3523.         }
  3524.         return S_FALSE;
  3525.     }
  3526.     virtual HRESULT    GetIndexofPropIdinPropSet(ULONG iCurSet, DBPROPID dwPropertyId, ULONG* piCurPropId)
  3527.     {
  3528.         ATLASSERT(piCurPropId);
  3529.         UPROPINFO* pUPropInfo = m_pUPropSet[iCurSet].pUPropInfo;
  3530.         for(ULONG ul=0; ul<m_pUPropSet[iCurSet].cUPropInfo; ul++)
  3531.         {
  3532.             if( dwPropertyId == pUPropInfo[ul].dwPropId )
  3533.             {
  3534.                 *piCurPropId = ul;
  3535.                 // Test to see if the property is supported for this
  3536.                 // instantiation
  3537.                 return (TESTBIT(&(m_rgdwSupported[iCurSet * m_cElemPerSupported]), ul)) ? S_OK : S_FALSE;
  3538.             }
  3539.         }
  3540.  
  3541.         return S_FALSE;
  3542.     }
  3543.     virtual HRESULT    SetPassThrough(const DBPROPSET* pPropSet)
  3544.     {
  3545.         ATLASSERT(pPropSet);
  3546.  
  3547.         DBPROP*    pProp = pPropSet->rgProperties;
  3548.  
  3549.         //Default implementation just sets all properties as NOTSUPPORTED
  3550.         for( ULONG ul=0; ul<pPropSet->cProperties; ul++, pProp++ )
  3551.             pProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
  3552.  
  3553.         return DB_E_ERRORSOCCURRED;
  3554.     }
  3555.  
  3556.     HRESULT    GetDefaultValue(ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar)
  3557.     {
  3558.         if (pdwOption == NULL || pVar == NULL)
  3559.             return E_INVALIDARG;
  3560.  
  3561.         ULONG cUPropSet = 0, cElemPerSupported =0;
  3562.         int cSets = (int)T::_GetPropSet(NULL, &cElemPerSupported);
  3563.         UPROPSET* pPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  3564.         if (pPropSet == NULL) 
  3565.             return E_OUTOFMEMORY;
  3566.         pPropSet = T::_GetPropSet(&cUPropSet, &cElemPerSupported, pPropSet);
  3567.  
  3568.         ATLASSERT(iPropSet < cUPropSet);
  3569.         for (ULONG iProp = 0; iProp < pPropSet[iPropSet].cUPropInfo; iProp++)
  3570.         {
  3571.             UPROPINFO& rInfo = pPropSet[iPropSet].pUPropInfo[iProp];
  3572.             if (rInfo.dwPropId == dwPropId)
  3573.             {
  3574.                 pVar->vt = rInfo.VarType;
  3575.                 *pdwOption = rInfo.dwOption;
  3576.                 switch(rInfo.VarType)
  3577.                 {
  3578.                 case VT_BSTR:
  3579.                     pVar->bstrVal = SysAllocString(rInfo.szVal);
  3580.                     break;
  3581.                 default:
  3582.                     pVar->lVal = rInfo.dwVal;
  3583.                     break;
  3584.                 }
  3585.                 CoTaskMemFree(pPropSet);
  3586.                 return S_OK;
  3587.             }
  3588.         }
  3589.         CoTaskMemFree(pPropSet);
  3590.         return E_FAIL;  
  3591.     }
  3592.     virtual HRESULT    IsValidValue(ULONG /*iCurSet*/, DBPROP* pDBProp)
  3593.     {
  3594.         ATLASSERT(pDBProp != NULL);
  3595.         CComVariant var = pDBProp->vValue;
  3596.         if (var.vt == VT_BOOL)
  3597.         {
  3598.             if (var.boolVal != VARIANT_TRUE && var.boolVal != VARIANT_FALSE)
  3599.                 return S_FALSE;
  3600.         }
  3601.  
  3602.         return S_OK;
  3603.     }
  3604.  
  3605.     virtual HRESULT OnPropertyChanged(ULONG /*iCurSet*/, DBPROP* /*pDBProp*/)
  3606.     {
  3607.         return S_OK;
  3608.     }
  3609.  
  3610.     virtual HRESULT    InitUPropSetsSupported()
  3611.     {
  3612.         ULONG cPropSet = 0, cElemsPerSupported = 0;
  3613.         int cSets = (int)T::_GetPropSet(NULL, &cElemsPerSupported);
  3614.         UPROPSET* pPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
  3615.         if (pPropSet == NULL) 
  3616.             return E_OUTOFMEMORY;
  3617.         pPropSet = T::_GetPropSet(&cPropSet, &cElemsPerSupported, pPropSet);
  3618.         memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD));
  3619.         CoTaskMemFree(pPropSet);
  3620.         return S_OK;
  3621.     }
  3622.     HRESULT GetIndexOfPropertyInSet(const GUID* pPropSet, DBPROPID dwPropertyId, ULONG* piCurPropId, ULONG* piCurSet)
  3623.     {
  3624.         HRESULT hr = GetIndexofPropSet(pPropSet, piCurSet);
  3625.         if (hr == S_FALSE)
  3626.             return hr;
  3627.         UPROPINFO* pUPropInfo = m_pUPropSet[*piCurSet].pUPropInfo;
  3628.         for(ULONG ul=0; ul<m_pUPropSet[*piCurSet].cUPropInfo; ul++)
  3629.         {
  3630.             if( dwPropertyId == pUPropInfo[ul].dwPropId )
  3631.                 *piCurPropId = ul;
  3632.             return S_OK;
  3633.         }
  3634.  
  3635.         return S_FALSE;
  3636.     }
  3637.     HRESULT SetSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId)
  3638.     {
  3639.         ULONG iCurPropId, iCurSet;
  3640.  
  3641.         if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
  3642.         {
  3643.             m_rgdwSupported[iCurSet * m_cElemPerSupported] |= 1 << iCurPropId;
  3644.             return S_OK;
  3645.         }
  3646.         return S_FALSE;
  3647.     }
  3648.  
  3649.     HRESULT ClearSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId)
  3650.     {
  3651.         ULONG iCurPropId, iCurSet;
  3652.  
  3653.         if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
  3654.         {
  3655.             m_rgdwSupported[iCurSet * m_cElemPerSupported] &= ~( 1 << iCurPropId);
  3656.             return S_OK;
  3657.         }
  3658.         return S_FALSE;
  3659.     }
  3660.  
  3661.     HRESULT TestSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId, bool& bSet)
  3662.     {
  3663.         ULONG iCurPropId, iCurSet;
  3664.  
  3665.         if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
  3666.         {
  3667.             bSet = (m_rgdwSupported[iCurSet * m_cElemPerSupported] & ( 1 << iCurPropId)) != 0;
  3668.             return S_OK;
  3669.         }
  3670.         return S_FALSE;
  3671.     }
  3672.     void CopyUPropSetsSupported(DWORD* rgdwSupported)
  3673.     {
  3674.         memcpy(rgdwSupported, m_rgdwSupported, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD)); 
  3675.     }
  3676.     void CopyPropsInError(DWORD* rgdwSupported)
  3677.     {
  3678.         memcpy(rgdwSupported, m_rgdwPropsInError, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD)); 
  3679.     }
  3680.     void CopyUPropInfo(ULONG iPropSet, UPROPINFO** rgpUPropInfo)
  3681.     {
  3682.         ATLASSERT( rgpUPropInfo );
  3683.         ATLASSERT( iPropSet < m_cUPropSet );
  3684.         memcpy(rgpUPropInfo, m_pUProp[iPropSet].rgpUPropInfo, m_pUProp[iPropSet].cPropIds * sizeof(UPROPINFO*));
  3685.     }
  3686. };
  3687.  
  3688. // IDBPropertiesImpl
  3689. // IDBProperties <- IUnknown
  3690. template <class T>
  3691. class ATL_NO_VTABLE IDBPropertiesImpl : public IDBProperties, public CUtlProps<T>
  3692. {
  3693. public:
  3694.     STDMETHOD(GetProperties)(ULONG cPropertySets,
  3695.                              const DBPROPIDSET rgPropertySets[],
  3696.                              ULONG *pcProperties,
  3697.                              DBPROPSET **prgProperties)
  3698.     {
  3699.         ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::GetProperties\n");
  3700.         T* pT = (T*)this;
  3701.         HRESULT hr = GetPropertiesArgChk(cPropertySets, rgPropertySets, pcProperties, prgProperties);
  3702.         if (FAILED(hr))
  3703.             return hr;
  3704.  
  3705.         if(SUCCEEDED(hr))
  3706.         {
  3707.             // Check for other invalid arguments 
  3708.             for (ULONG i=0; i<cPropertySets; i++)
  3709.             {
  3710.                 if (InlineIsEqualGUID(rgPropertySets[i].guidPropertySet, DBPROPSET_PROPERTIESINERROR))
  3711.                     if (pcProperties != NULL || prgProperties != NULL || cPropertySets > 1)
  3712.                         return E_INVALIDARG;
  3713.             }
  3714.         }
  3715.  
  3716.         if (SUCCEEDED(hr))
  3717.         {
  3718.             const GUID* ppGuid[3];
  3719.             if (pT->m_dwStatus & DSF_INITIALIZED)
  3720.             {
  3721.                 ppGuid[0] = &DBPROPSET_DBINIT;
  3722.                 ppGuid[1] = &DBPROPSET_DATASOURCE;
  3723.                 ppGuid[2] = &DBPROPSET_DATASOURCEINFO;
  3724.                 hr = CUtlProps<T>::GetProperties(cPropertySets, rgPropertySets,
  3725.                             pcProperties, prgProperties, 3, ppGuid);
  3726.             }
  3727.             else
  3728.             {
  3729.                 ppGuid[0] = &DBPROPSET_DBINIT;
  3730.                 hr = CUtlProps<T>::GetProperties(cPropertySets, rgPropertySets, 
  3731.                             pcProperties, prgProperties, 1, ppGuid);
  3732.             }
  3733.         }
  3734.  
  3735.         return hr;
  3736.     }
  3737.  
  3738.     STDMETHOD(GetPropertyInfo)(ULONG cPropertySets,
  3739.                                const DBPROPIDSET rgPropertySets[],
  3740.                                ULONG *pcPropertyInfoSets,
  3741.                                DBPROPINFOSET **prgPropertyInfoSets,
  3742.                                OLECHAR **ppDescBuffer)
  3743.     {
  3744.         ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::GetPropertyInfo\n");
  3745.         T* pT = (T*)this;
  3746.  
  3747.         if (pT->m_pCUtlPropInfo == NULL)
  3748.         {
  3749.             // Go ahead and create the m_pCUtlPropInfo but do not change the
  3750.             // Initialized status of the provider (see IDBInitialize::Initialize).
  3751.             ATLTRACE2(atlTraceDBProvider, 0, "m_pCUtlPropInfo == NULL\n");
  3752.             pT->Lock();
  3753.             delete pT->m_pCUtlPropInfo;
  3754.             ATLTRY(pT->m_pCUtlPropInfo = new CUtlPropInfo<T>())
  3755.             pT->Unlock();
  3756.             if (pT->m_pCUtlPropInfo == NULL)
  3757.             {
  3758.                 ATLTRACE2(atlTraceDBProvider, 0, "IDBProperties::GetPropertyInfo Error : OOM\n");
  3759.                 return E_OUTOFMEMORY;
  3760.             }
  3761.             HRESULT hr = pT->m_pCUtlPropInfo->FInit();
  3762.             if (hr != S_OK)
  3763.             {
  3764.                 pT->Lock();
  3765.                 delete pT->m_pCUtlPropInfo;
  3766.                 pT->m_pCUtlPropInfo = NULL;
  3767.                 pT->Unlock();
  3768.             }
  3769.         }
  3770.  
  3771.         // Initialize 
  3772.         if( pcPropertyInfoSets )
  3773.             *pcPropertyInfoSets = 0;
  3774.         if( prgPropertyInfoSets )
  3775.             *prgPropertyInfoSets = NULL;
  3776.         if( ppDescBuffer )
  3777.             *ppDescBuffer = NULL;
  3778.  
  3779.         // Check Arguments
  3780.         if( ((cPropertySets > 0) && !rgPropertySets) ||
  3781.             !pcPropertyInfoSets || !prgPropertyInfoSets )
  3782.             return E_INVALIDARG;
  3783.  
  3784.  
  3785.  
  3786.         // New argument check for > 1 cPropertyIDs and NULL pointer for 
  3787.         // array of property ids.
  3788.         const DWORD SPECIAL_GROUP        = 1;
  3789.         const DWORD SPECIAL_SINGLE        = 2;
  3790.         const DWORD SPECIALS            = SPECIAL_GROUP | SPECIAL_SINGLE;
  3791.         DWORD dwSpecial = 0;
  3792.         for(ULONG ul=0; ul<cPropertySets; ul++)
  3793.         {
  3794.             if( (rgPropertySets[ul].guidPropertySet == DBPROPSET_DATASOURCEALL) ||
  3795.                 (rgPropertySets[ul].guidPropertySet == DBPROPSET_DATASOURCEINFOALL) ||
  3796.                 (rgPropertySets[ul].guidPropertySet == DBPROPSET_DBINITALL) ||
  3797.                 (rgPropertySets[ul].guidPropertySet == DBPROPSET_SESSIONALL) ||
  3798.                 (rgPropertySets[ul].guidPropertySet == DBPROPSET_ROWSETALL) )
  3799.                 dwSpecial |= SPECIAL_GROUP;
  3800.             else
  3801.                 dwSpecial |= SPECIAL_SINGLE;
  3802.                                                 
  3803.             if( (dwSpecial == SPECIALS) ||
  3804.                 (rgPropertySets[ul].cPropertyIDs && !(rgPropertySets[ul].rgPropertyIDs)) )
  3805.                 return E_INVALIDARG;
  3806.         }
  3807.  
  3808.         if (pT->m_dwStatus & DSF_INITIALIZED)
  3809.             return pT->m_pCUtlPropInfo->GetPropertyInfo(cPropertySets, rgPropertySets, 
  3810.                                               pcPropertyInfoSets, prgPropertyInfoSets, 
  3811.                                               ppDescBuffer, true);
  3812.         else
  3813.             return pT->m_pCUtlPropInfo->GetPropertyInfo(cPropertySets, rgPropertySets, 
  3814.                                               pcPropertyInfoSets, prgPropertyInfoSets, 
  3815.                                               ppDescBuffer, false, &DBPROPSET_DBINITALL);
  3816.  
  3817.     }
  3818.  
  3819.     STDMETHOD(SetProperties)(ULONG cPropertySets,
  3820.                              DBPROPSET rgPropertySets[])
  3821.     {
  3822.         ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::SetProperties\n");
  3823.         HRESULT    hr;
  3824.         DBPROPSET* pdbPropSet = NULL;
  3825.         ULONG iProp;
  3826.         const GUID* ppGuid[3];
  3827.         T* pT = (T*)this;
  3828.  
  3829.         // Quick return if the Count of Properties is 0
  3830.         if( cPropertySets == 0 )
  3831.             return S_OK;
  3832.  
  3833.         hr = CUtlProps<T>::SetPropertiesArgChk(cPropertySets, rgPropertySets);
  3834.         if(SUCCEEDED(hr))
  3835.         {
  3836.             // We need to handle the DBINIT properties specially after being initialized.
  3837.             // - they should be treated as NOTSETTABLE at this point.
  3838.             if( pT->m_dwStatus & DSF_INITIALIZED )
  3839.             {
  3840.                 ATLASSERT(cPropertySets);
  3841.  
  3842.                 BOOL fFoundDBINIT = FALSE;
  3843.  
  3844.                 // Allocate a DBPROPSET structure of equal size
  3845.                 ATLTRY(pdbPropSet = new DBPROPSET[cPropertySets])
  3846.                 if( pdbPropSet == NULL )
  3847.                     return E_OUTOFMEMORY;
  3848.  
  3849.                 for(ULONG iNewSet=0,iSet=0; iSet<cPropertySets; iSet++)
  3850.                 {
  3851.                     // Remove any DBPROPSET_DBINIT values and mark them all
  3852.                     // as not settable
  3853.                     if( (rgPropertySets[iSet].guidPropertySet == DBPROPSET_DBINIT))
  3854.                     {
  3855.                         fFoundDBINIT = TRUE;
  3856.                         for(iProp=0; iProp<rgPropertySets[iSet].cProperties; iProp++)
  3857.                             rgPropertySets[iSet].rgProperties[iProp].dwStatus = DBPROPSTATUS_NOTSETTABLE;
  3858.                     }
  3859.                     else
  3860.                     {
  3861.                         // If not DBPROPSET_DBINIT then copy the DBPROPSET values
  3862.                         memcpy(&pdbPropSet[iNewSet++], &rgPropertySets[iSet], sizeof(DBPROPSET));
  3863.                     }
  3864.                 }
  3865.  
  3866.                 // If we have no propertyset to pass on to the property handler, we
  3867.                 // can exit
  3868.                 if( iNewSet == 0 )
  3869.                 {
  3870.                     hr = DB_E_ERRORSOCCURRED;
  3871.                     goto exit;
  3872.                 }
  3873.  
  3874.                 ppGuid[0] = &DBPROPSET_DBINIT;
  3875.                 ppGuid[1] = &DBPROPSET_DATASOURCE;
  3876.                 ppGuid[2] = &DBPROPSET_DATASOURCEINFO;
  3877.                 hr = CUtlProps<T>::SetProperties(0, iNewSet, pdbPropSet, 3, ppGuid);
  3878.  
  3879.                 // If we have determined that one of the property sets was DBINIT, we may
  3880.                 // need to fixup the returned hr value.
  3881.                 if( fFoundDBINIT && SUCCEEDED(hr))
  3882.                     hr = DB_S_ERRORSOCCURRED;
  3883.             }
  3884.             else
  3885.             {
  3886.                 // Note that m_pCUtlProps knows about initialization,
  3887.                 // so we don't have to here.
  3888.                 ppGuid[0] = &DBPROPSET_DBINIT;
  3889.                 hr = CUtlProps<T>::SetProperties(0, cPropertySets, rgPropertySets,
  3890.                         1, ppGuid);
  3891.             }
  3892.         }
  3893.  
  3894. exit:
  3895.         delete[] pdbPropSet;
  3896.         return hr;
  3897.     }
  3898. };
  3899.  
  3900.  
  3901. #define BEGIN_SCHEMA_MAP(SchemaClass) \
  3902.     typedef SchemaClass _SchemaClass; \
  3903.     HRESULT _SchemaSupport(GUID** ppGuid, \
  3904.                            IUnknown *pUnkOuter, \
  3905.                             REFIID rguidSchema, \
  3906.                            ULONG cRestrictions, \
  3907.                            const VARIANT rgRestrictions[], \
  3908.                            REFIID riid, \
  3909.                            ULONG cPropertySets, \
  3910.                            DBPROPSET rgPropertySets[], \
  3911.                            IUnknown **ppRowset) \
  3912.     { \
  3913.     int cGuids = 0; \
  3914.     HRESULT hr = S_OK; \
  3915.     if (ppGuid != NULL) \
  3916.         *ppGuid = NULL;
  3917.  
  3918. #define SCHEMA_ENTRY(guid, rowsetClass) \
  3919.     if (ppGuid != NULL && SUCCEEDED(hr)) \
  3920.     { \
  3921.         cGuids++; \
  3922.         *ppGuid = (GUID*)CoTaskMemRealloc(*ppGuid, cGuids * sizeof(GUID)); \
  3923.         hr = (*ppGuid == NULL) ? E_OUTOFMEMORY : S_OK; \
  3924.         if (SUCCEEDED(hr)) \
  3925.             (*ppGuid)[cGuids - 1] = guid; \
  3926.     } \
  3927.     else \
  3928.     { \
  3929.         if (InlineIsEqualGUID(guid, rguidSchema)) \
  3930.         { \
  3931.             rowsetClass* pRowset; \
  3932.             hr =  CreateSchemaRowset(pUnkOuter, cRestrictions, \
  3933.                                rgRestrictions, riid, cPropertySets, \
  3934.                                rgPropertySets, ppRowset, pRowset); \
  3935.             return hr; \
  3936.         } \
  3937.     }
  3938.  
  3939. #define END_SCHEMA_MAP() \
  3940.         if (ppGuid != NULL) \
  3941.             return hr; \
  3942.         return E_INVALIDARG; \
  3943.     }
  3944.  
  3945.  
  3946. template <class SessionClass>
  3947. class  IDBSchemaRowsetImpl: public IDBSchemaRowset
  3948. {
  3949. public:
  3950.  
  3951.     template <class SchemaRowsetClass>
  3952.     HRESULT CreateSchemaRowset(IUnknown *pUnkOuter, ULONG cRestrictions,
  3953.                                const VARIANT rgRestrictions[], REFIID riid, 
  3954.                                ULONG cPropertySets, DBPROPSET rgPropertySets[],
  3955.                                IUnknown** ppRowset, SchemaRowsetClass*& pSchemaRowset)
  3956.     {
  3957.         SessionClass* pT = (SessionClass*) this;
  3958.         HRESULT hr, hrProps = S_OK;
  3959.         if (ppRowset != NULL)
  3960.             *ppRowset = NULL;
  3961.         if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  3962.             return DB_E_NOAGGREGATION;
  3963.  
  3964.         CComPolyObject<SchemaRowsetClass>* pPolyObj; 
  3965.         if (FAILED(hr = CComPolyObject<SchemaRowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
  3966.             return hr;
  3967.         // Ref the created COM object and Auto release it on failure
  3968.         CComPtr<IUnknown> spUnk;
  3969.         hr = pPolyObj->m_contained.QueryInterface(&spUnk);
  3970.         if (FAILED(hr))
  3971.         {
  3972.             delete pPolyObj; // must hand delete as it is not ref'd
  3973.             return hr;
  3974.         }
  3975.         // Get a pointer to the Rowset instance
  3976.         pSchemaRowset = &(pPolyObj->m_contained);
  3977.         hr = pSchemaRowset->FInit();
  3978.         if (FAILED(hr))
  3979.             return hr;
  3980.         hr = pSchemaRowset->SetPropertiesArgChk(cPropertySets, rgPropertySets);
  3981.         if (FAILED(hr))
  3982.             return hr;
  3983.         const GUID* ppGuid[1]; 
  3984.         ppGuid[0] = &DBPROPSET_ROWSET; 
  3985.  
  3986.         // Call SetProperties.  The true in the last parameter indicates 
  3987.         // the special behavior that takes place on rowset creation (i.e.
  3988.         // it succeeds as long as any of the properties were not marked
  3989.         // as DBPROPS_REQUIRED.
  3990.  
  3991.         hrProps = pSchemaRowset->SetProperties(0, cPropertySets, rgPropertySets, 
  3992.                                             1, ppGuid, true);
  3993.         if (FAILED(hrProps))
  3994.             return hrProps;
  3995.  
  3996.         if (ppRowset == NULL)
  3997.             return (hrProps == DB_S_ERRORSOCCURRED) ? DB_E_ERRORSOCCURRED : hr;
  3998.  
  3999.         pSchemaRowset->SetSite(((SessionClass*)this)->GetUnknown());
  4000.         LONG cRowsAffected;
  4001.         hr = pSchemaRowset->Execute(&cRowsAffected, cRestrictions, rgRestrictions);
  4002.         if (FAILED(hr))
  4003.             return hr;
  4004.         if (InlineIsEqualGUID(riid, IID_NULL))
  4005.             return E_NOINTERFACE;
  4006.         hr = pPolyObj->QueryInterface(riid, (void**)ppRowset);
  4007.         if (FAILED(hr))
  4008.         {
  4009.             *ppRowset = NULL;
  4010.             return hr;
  4011.         }
  4012.         return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr;
  4013.     }
  4014.  
  4015.  
  4016.     void SetRestrictions(ULONG cRestrictions, GUID* /*rguidSchema*/, ULONG* rgRestrictions)
  4017.     {
  4018.         memset(rgRestrictions, 0, sizeof(ULONG) * cRestrictions);
  4019.     }
  4020.  
  4021.     STDMETHOD(GetSchemas)(ULONG * pcSchemas, GUID ** prgSchemas, ULONG** prgRest)
  4022.     {
  4023.         ATLTRACE2(atlTraceDBProvider, 0, "IDBSchemaRowsetImpl::GetSchemas\n");
  4024.         if (pcSchemas != NULL)
  4025.             *pcSchemas = 0;
  4026.         if (prgSchemas != NULL)
  4027.             *prgSchemas = NULL;
  4028.         if (pcSchemas == NULL || prgSchemas == NULL) 
  4029.             return E_INVALIDARG;
  4030.  
  4031.         SessionClass* pT = (SessionClass*)this;
  4032.  
  4033.         HRESULT hr = pT->_SchemaSupport(prgSchemas, NULL, GUID_NULL, 0, 
  4034.                                         NULL, GUID_NULL, 0, NULL, NULL);
  4035.         if (FAILED(hr))
  4036.             return hr;
  4037.  
  4038.         CComPtr<IMalloc> spMalloc;
  4039.         hr = CoGetMalloc(1, &spMalloc);
  4040.         if (FAILED(hr))
  4041.         {
  4042.             CoTaskMemFree(*prgSchemas);
  4043.             *prgSchemas = NULL;
  4044.             return hr;
  4045.         }
  4046.         *pcSchemas = spMalloc->GetSize(prgSchemas);
  4047.  
  4048.         if (prgRest != NULL)
  4049.         {
  4050.             // The OLE DB spec states that if prgRest == NULL not to return array
  4051.             // but it also says that is E_INVALIDARG, so doing first
  4052.             *prgRest = (ULONG*) spMalloc->Alloc(sizeof(ULONG) * (*pcSchemas));
  4053.             if (*prgRest == NULL)
  4054.             {
  4055.                 spMalloc->Free(*prgSchemas);
  4056.                 *prgSchemas = NULL;
  4057.                 return E_OUTOFMEMORY;
  4058.             }
  4059.             pT->SetRestrictions(*pcSchemas, *prgSchemas, *prgRest);
  4060.         }
  4061.         return hr;
  4062.     }
  4063.     STDMETHOD(GetRowset)(IUnknown *pUnkOuter, REFGUID rguidSchema, ULONG cRestrictions,
  4064.                          const VARIANT rgRestrictions[], REFIID riid, ULONG cPropertySets,
  4065.                          DBPROPSET rgPropertySets[], IUnknown **ppRowset)
  4066.     {
  4067.         ATLTRACE2(atlTraceDBProvider, 0, "IDBSchemaRowsetImpl::GetRowset\n");
  4068.         SessionClass* pT = (SessionClass*)this;
  4069.         return  pT->_SchemaSupport(NULL, pUnkOuter, rguidSchema, cRestrictions,
  4070.                                    rgRestrictions, riid, cPropertySets,
  4071.                                    rgPropertySets, ppRowset);
  4072.     
  4073.     }
  4074.  
  4075. };
  4076.  
  4077. // IDBCreateCommandImpl
  4078. template <class T, class CommandClass>
  4079. class ATL_NO_VTABLE IDBCreateCommandImpl : public IDBCreateCommand
  4080. {
  4081. public:
  4082.     STDMETHOD(CreateCommand)(IUnknown *pUnkOuter,
  4083.                              REFIID riid,
  4084.                              IUnknown **ppvCommand)
  4085.     {
  4086.         ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateCommandImpl::CreateCommand\n");
  4087.         if (ppvCommand == NULL)
  4088.             return E_INVALIDARG;
  4089.         HRESULT hr;
  4090.         CComPolyObject<CommandClass>* pCommand;
  4091.  
  4092.         // You can't QI for an interface other than IUnknown when aggregating 
  4093.         // and creating the object.  You might ask for your own interface, 
  4094.         // which would be bad.  Note, we return DB_E_NOAGGREGATION instead of
  4095.         // CLASS_E_NOAGGREGATION due to OLE DB constraints.
  4096.         if (pUnkOuter != NULL && !InlineIsEqualUnknown(riid))
  4097.             return DB_E_NOAGGREGATION;
  4098.  
  4099.         hr = CComPolyObject<CommandClass>::CreateInstance(pUnkOuter, &pCommand);
  4100.         if (FAILED(hr))
  4101.             return hr;
  4102.         // Ref the created COM object and Auto release it on failure
  4103.         CComPtr<IUnknown> spUnk;
  4104.         hr = pCommand->m_contained.QueryInterface(&spUnk);
  4105.         if (FAILED(hr))
  4106.         {
  4107.             delete pCommand; // must hand delete as it is not ref'd
  4108.             return hr;
  4109.         }
  4110.         ATLASSERT(pCommand->m_contained.m_spUnkSite == NULL);
  4111.         pCommand->m_contained.SetSite(this);
  4112.         hr = pCommand->QueryInterface(riid, (void**)ppvCommand);
  4113.         return hr;
  4114.     }
  4115.  
  4116. };
  4117.  
  4118.  
  4119. // IGetDataSourceImpl
  4120. template <class T>
  4121. class ATL_NO_VTABLE IGetDataSourceImpl : public IGetDataSource
  4122. {
  4123. public:
  4124.     STDMETHOD(GetDataSource)(REFIID riid,
  4125.                              IUnknown **ppDataSource)
  4126.     {
  4127.         ATLTRACE2(atlTraceDBProvider, 0, "IGetDataSourceImpl::GetDataSource\n");
  4128.         if (ppDataSource == NULL)
  4129.             return E_INVALIDARG;
  4130.         T* pT = (T*) this;
  4131.         ATLASSERT(pT->m_spUnkSite != NULL);
  4132.         return pT->m_spUnkSite->QueryInterface(riid, (void**)ppDataSource);
  4133.     }
  4134. };
  4135.  
  4136.  
  4137. // IOpenRowsetImpl
  4138. template <class SessionClass>
  4139. class IOpenRowsetImpl : public IOpenRowset
  4140. {
  4141. public:
  4142.     template <class RowsetClass>
  4143.     HRESULT CreateRowset(IUnknown* pUnkOuter, 
  4144.                          DBID *pTableID, DBID *pIndexID,
  4145.                          REFIID riid, 
  4146.                          ULONG cPropertySets, DBPROPSET rgPropertySets[],
  4147.                          IUnknown** ppRowset, 
  4148.                          RowsetClass*& pRowsetObj)
  4149.     {
  4150.         HRESULT hr, hrProps = S_OK;
  4151.         if (ppRowset != NULL)
  4152.             *ppRowset = NULL;
  4153.         if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  4154.             return DB_E_NOAGGREGATION;
  4155.         CComPolyObject<RowsetClass>* pPolyObj; 
  4156.         if (FAILED(hr = CComPolyObject<RowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
  4157.             return hr;
  4158.         // Ref the created COM object and Auto release it on failure
  4159.         CComPtr<IUnknown> spUnk;
  4160.         hr = pPolyObj->m_contained.QueryInterface(&spUnk);
  4161.         if (FAILED(hr))
  4162.         {
  4163.             delete pPolyObj; // must hand delete as it is not ref'd
  4164.             return hr;
  4165.         }
  4166.         // Get a pointer to the Rowset instance
  4167.         pRowsetObj = &(pPolyObj->m_contained);
  4168.         hr = pRowsetObj->FInit();
  4169.         if (FAILED(hr))
  4170.             return hr;
  4171.         hr = pRowsetObj->SetPropertiesArgChk(cPropertySets, rgPropertySets);
  4172.         if (FAILED(hr))
  4173.             return hr;
  4174.  
  4175.         const GUID* ppGuid[1]; 
  4176.         ppGuid[0] = &DBPROPSET_ROWSET; 
  4177.  
  4178.         // Call SetProperties.  The true in the last parameter indicates 
  4179.         // the special behavior that takes place on rowset creation (i.e.
  4180.         // it succeeds as long as any of the properties were not marked
  4181.         // as DBPROPS_REQUIRED.
  4182.  
  4183.         hrProps = pRowsetObj->SetProperties(0, cPropertySets, rgPropertySets, 
  4184.                                             1, ppGuid, true);
  4185.         if (FAILED(hrProps))
  4186.             return hrProps;
  4187.  
  4188.         pRowsetObj->SetSite(((SessionClass*)this)->GetUnknown());
  4189.  
  4190.         hr = pRowsetObj->SetCommandText(pTableID, pIndexID);
  4191.         if (FAILED(hr))
  4192.             return hr;
  4193.         LONG cRowsAffected;
  4194.         if (FAILED(hr = pRowsetObj->Execute(NULL, &cRowsAffected)))
  4195.             return hr;
  4196.         if (InlineIsEqualGUID(riid, IID_NULL))
  4197.         {
  4198.             return E_NOINTERFACE;
  4199.         }
  4200.         else
  4201.         {
  4202.             if (ppRowset == NULL)
  4203.                 return (hrProps == DB_S_ERRORSOCCURRED) ? DB_E_ERRORSOCCURRED : hr;
  4204.  
  4205.             hr = pPolyObj->QueryInterface(riid, (void**)ppRowset);
  4206.         }
  4207.  
  4208.         if (FAILED(hr))
  4209.         {
  4210.             *ppRowset = NULL;
  4211.             return hr;
  4212.         }
  4213.         return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr;
  4214.     }
  4215.  
  4216. };
  4217.  
  4218. // IColumnsInfoImpl
  4219. template <class T>
  4220. class ATL_NO_VTABLE IColumnsInfoImpl : 
  4221.     public IColumnsInfo,
  4222.     public CDBIDOps
  4223. {
  4224. public:
  4225.  
  4226.     HRESULT CheckCommandText()
  4227.     {
  4228.         T* pT = (T*)this;
  4229.         HRESULT hr = E_FAIL;
  4230.         CComPtr<ICommandText> spText;
  4231.         if (SUCCEEDED(hr = pT->QueryInterface(IID_ICommandText, (void**)&spText)))
  4232.         {
  4233.             LPOLESTR szCommand;
  4234.             hr = spText->GetCommandText(NULL, &szCommand);
  4235.             if (SUCCEEDED(hr))
  4236.                 CoTaskMemFree(szCommand);
  4237.         }
  4238.         return hr;
  4239.     }
  4240.     STDMETHOD(GetColumnInfo)(ULONG *pcColumns,
  4241.                              DBCOLUMNINFO **prgInfo,
  4242.                              OLECHAR **ppStringsBuffer)
  4243.     {
  4244.         ATLTRACE2(atlTraceDBProvider, 0, "IColumnsInfoImpl::GetColumnInfo\n");
  4245.         T* pT = (T*)this;
  4246.         if (pcColumns == NULL || prgInfo == NULL || ppStringsBuffer == NULL)
  4247.         {
  4248.             if (prgInfo != NULL)
  4249.                 *prgInfo = NULL;
  4250.             if (ppStringsBuffer != NULL)
  4251.                 *ppStringsBuffer = NULL;
  4252.             if (pcColumns != NULL)
  4253.                 *pcColumns = NULL;
  4254.             return E_INVALIDARG;
  4255.         }
  4256.         
  4257.         // NULL out pointers in case of an error
  4258.         *prgInfo = NULL;
  4259.         *ppStringsBuffer = NULL;
  4260.         *pcColumns = 0;
  4261.  
  4262.         if (pT->CheckCommandText() == DB_E_NOCOMMAND)
  4263.             return DB_E_NOCOMMAND;
  4264.         ATLCOLUMNINFO* pInfo = T::GetColumnInfo(pT, pcColumns);
  4265.         ATLASSERT(pInfo != NULL);
  4266.         *prgInfo = (DBCOLUMNINFO*)CoTaskMemAlloc(*pcColumns * sizeof(DBCOLUMNINFO));
  4267.         if (*prgInfo != NULL)
  4268.         {
  4269.             for (ULONG iCol = 0, cwRequired = 0; iCol < *pcColumns; iCol++)
  4270.             {
  4271.                 memcpy(&((*prgInfo)[iCol]), &pInfo[iCol], sizeof(DBCOLUMNINFO));
  4272.                 if (pInfo[iCol].pwszName)
  4273.                 {
  4274.                     cwRequired += wcslen(pInfo[iCol].pwszName) + 1;
  4275.                 }
  4276.             }
  4277.             *ppStringsBuffer = (OLECHAR*)CoTaskMemAlloc(cwRequired*sizeof(OLECHAR));
  4278.             if (*ppStringsBuffer)
  4279.             {
  4280.                 for (ULONG iCol = 0, iOffset = 0; iCol < *pcColumns; iCol++)
  4281.                 {
  4282.                     if (pInfo[iCol].pwszName)
  4283.                     {
  4284.                         lstrcpyW(*ppStringsBuffer + iOffset,  pInfo[iCol].pwszName);
  4285.                         iOffset += wcslen(*ppStringsBuffer + iOffset) + 1;
  4286.                     }
  4287.                 }
  4288.                 return S_OK;
  4289.             }
  4290.             else
  4291.             {
  4292.                 ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate string buffer\n"));
  4293.                 CoTaskMemFree(*prgInfo);
  4294.                 *prgInfo = NULL;
  4295.                 *pcColumns = 0;
  4296.                 return E_OUTOFMEMORY;
  4297.             }
  4298.         }
  4299.         else
  4300.         {
  4301.             ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate ColumnInfo array\n"));
  4302.             *prgInfo = NULL;
  4303.             *pcColumns = 0;
  4304.             return E_OUTOFMEMORY;
  4305.         }
  4306.  
  4307.     }
  4308.  
  4309.     STDMETHOD(MapColumnIDs)(ULONG cColumnIDs,
  4310.                             const DBID rgColumnIDs[],
  4311.                             ULONG rgColumns[])
  4312.     {
  4313.         ATLTRACE2(atlTraceDBProvider, 0, "IColumnsInfoImpl::MapColumnIDs\n");
  4314.         USES_CONVERSION;
  4315.         if ((cColumnIDs != 0 && rgColumnIDs == NULL) || rgColumns == NULL)
  4316.             return E_INVALIDARG;
  4317.         if (CheckCommandText() == DB_E_NOCOMMAND)
  4318.             return DB_E_NOCOMMAND;
  4319.         ULONG cCols = 0;
  4320.         ULONG cColsInError = 0;
  4321.         HRESULT hr = S_OK;
  4322.         for (ULONG iColId = 0; iColId < cColumnIDs; iColId++)
  4323.         {
  4324.             ATLCOLUMNINFO* pInfo = T::GetColumnInfo((T*)this, &cCols);
  4325.             ULONG iColMapCur = 0;
  4326.             BOOL bDone = FALSE;
  4327.             while(iColMapCur < cCols && !bDone)
  4328.             {
  4329.                 hr = CompareDBIDs(&(pInfo[iColMapCur].columnid), &(rgColumnIDs[iColId]));
  4330.                 bDone = (hr == S_OK || FAILED(hr));
  4331.                 if (hr == S_OK)
  4332.                     rgColumns[iColId] = pInfo[iColMapCur].iOrdinal;
  4333.                 iColMapCur++;
  4334.             }
  4335.             if (!bDone || FAILED(hr))
  4336.             {
  4337.                 rgColumns[iColId] = DB_INVALIDCOLUMN;
  4338.                 cColsInError++;
  4339.             }
  4340.  
  4341.         }
  4342.         if (cColsInError > 0 && cColumnIDs == cColsInError) 
  4343.             return DB_E_ERRORSOCCURRED;
  4344.         if (cColsInError > 0 && cColsInError < cColumnIDs)
  4345.             return DB_S_ERRORSOCCURRED;
  4346.         return S_OK;
  4347.     }
  4348. };
  4349.  
  4350. //IConvertTypeImpl
  4351. template <class T>
  4352. class ATL_NO_VTABLE IConvertTypeImpl : public IConvertType, public CConvertHelper
  4353. {
  4354. public:
  4355.     STDMETHOD(CanConvert)(DBTYPE wFromType, DBTYPE wToType, DBCONVERTFLAGS dwConvertFlags)
  4356.     {
  4357.         ATLTRACE2(atlTraceDBProvider, 0, "IConvertTypeImpl::CanConvert\n");
  4358.         T* pT = (T*)this;
  4359.  
  4360.         // Check to see if conversion types are invalid.  Note, this is just a
  4361.         // quick test as it would be difficult to check each available type 
  4362.         // (as new DBTYPE values can be added).
  4363.         if ((wFromType & 0x8000) || (wToType & 0x8000))
  4364.             return E_INVALIDARG;
  4365.  
  4366.         // Determine if the flags are valid
  4367.         if (dwConvertFlags != DBCONVERTFLAGS_COLUMN && dwConvertFlags != 
  4368.                 DBCONVERTFLAGS_PARAMETER)
  4369.             return DB_E_BADCONVERTFLAG;
  4370.  
  4371.         if (dwConvertFlags == DBCONVERTFLAGS_PARAMETER)
  4372.         {
  4373.             // In the case where we are a rowset and ask for a parameter 
  4374.             // conversion, return DB_E_BADCONVERTFLAG
  4375.             if (!pT->m_bIsCommand)
  4376.                 return DB_E_BADCONVERTFLAG;
  4377.  
  4378.             // In the case where we are a command and ask for a parameter 
  4379.             // conversion and ICommandWithParameters is not supported, return 
  4380.             // S_FALSE.  We just can't convert them.
  4381.             if (!pT->m_bHasParamaters)
  4382.                 return S_FALSE;
  4383.         }
  4384.     
  4385.         // If we deal with a command and the user asks for a conversion on a rowset
  4386.         // the DBPROP_ROWSETCONVERSIONSONCOMMAND must be suppored and set to TRUE.
  4387.         if (pT->m_bIsCommand && dwConvertFlags == DBCONVERTFLAGS_COLUMN)
  4388.         {
  4389.             CDBPropIDSet set(DBPROPSET_DATASOURCEINFO);
  4390.             set.AddPropertyID(DBPROP_ROWSETCONVERSIONSONCOMMAND);
  4391.             DBPROPSET* pPropSet = NULL;
  4392.             ULONG ulPropSet = 0;
  4393.             HRESULT hr1 = S_OK;
  4394.  
  4395.             // Get a pointer into the session
  4396.             CComPtr<IGetDataSource> spDataSource = NULL;
  4397.             CComPtr<IDBProperties> spProps = NULL;
  4398.             
  4399.             // if any of these calls fail, we're either unable to retrieve the
  4400.             // property or it is unsupported.  Since the property is only on
  4401.             // the data source object, we use the IObjectWithSite interface to
  4402.             // get the session object and then the GetDataSource method to get
  4403.             // the data source object itself.
  4404.             if (FAILED(pT->GetSite(IID_IGetDataSource, (void**)&spDataSource)))
  4405.                 return DB_E_BADCONVERTFLAG;
  4406.             if (FAILED(spDataSource->GetDataSource(IID_IDBProperties, 
  4407.                 (IUnknown**)&spProps)))
  4408.                 return DB_E_BADCONVERTFLAG;
  4409.             if (FAILED(spProps->GetProperties(1, &set, &ulPropSet, &pPropSet)))
  4410.                 return DB_E_BADCONVERTFLAG;
  4411.  
  4412.             if (pPropSet != NULL)
  4413.             {
  4414.                 CComVariant var = pPropSet->rgProperties[0].vValue;
  4415.                 CoTaskMemFree(pPropSet->rgProperties);
  4416.                 CoTaskMemFree(pPropSet);
  4417.                 
  4418.                 if (var.boolVal == VARIANT_FALSE)
  4419.                     return DB_E_BADCONVERTFLAG;
  4420.             }
  4421.         }
  4422.         HRESULT hr = E_FAIL;
  4423.         if (m_spConvert != NULL)
  4424.         {
  4425.             hr = m_spConvert->CanConvert(wFromType, wToType);
  4426.         }
  4427.         return hr;
  4428.     }
  4429. };
  4430.  
  4431. template <class T, class PropClass = T>
  4432. class ATL_NO_VTABLE ICommandPropertiesImpl : 
  4433.     public ICommandProperties, 
  4434.     public CUtlProps<PropClass>
  4435. {
  4436. public:
  4437.     typedef PropClass _PropClass;
  4438.     
  4439.     STDMETHOD(GetProperties)(const ULONG cPropertyIDSets,
  4440.                              const DBPROPIDSET rgPropertyIDSets[],
  4441.                              ULONG *pcPropertySets,
  4442.                              DBPROPSET **prgPropertySets)
  4443.     {
  4444.         ATLTRACE2(atlTraceDBProvider, 0, "ICommandPropertiesImpl::GetProperties\n");
  4445.         HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
  4446.         const GUID* ppGuid[1];
  4447.         ppGuid[0] = &DBPROPSET_ROWSET;
  4448.         if(SUCCEEDED(hr))
  4449.             hr = CUtlProps<PropClass>::GetProperties(cPropertyIDSets, 
  4450.                     rgPropertyIDSets, pcPropertySets, prgPropertySets, 
  4451.                     1, ppGuid);
  4452.         return hr;
  4453.  
  4454.     }
  4455.  
  4456.     STDMETHOD(SetProperties)(ULONG cPropertySets,
  4457.                              DBPROPSET rgPropertySets[])
  4458.     {
  4459.         ATLTRACE2(atlTraceDBProvider, 0, "ICommandPropertiesImpl::SetProperties\n");
  4460.         HRESULT hr = SetPropertiesArgChk(cPropertySets, rgPropertySets);
  4461.         const GUID* ppGuid[1];
  4462.         ppGuid[0] = &DBPROPSET_ROWSET;
  4463.         if(SUCCEEDED(hr))
  4464.             hr = CUtlProps<PropClass>::SetProperties(0, cPropertySets, 
  4465.                     rgPropertySets, 1, ppGuid);
  4466.         return hr;
  4467.     }
  4468. };
  4469.  
  4470. template <class T>
  4471. class CRunTimeFree
  4472. {
  4473. public:
  4474.  
  4475.     static void Free(T* pData) 
  4476.     {
  4477.         delete [] pData;
  4478.     }
  4479. };
  4480.  
  4481. template <class T>
  4482. class CComFree
  4483. {
  4484. public:
  4485.  
  4486.     static void Free(T* pData) 
  4487.     {
  4488.         CoTaskMemFree(pData);
  4489.     }
  4490. };
  4491.      
  4492.  
  4493. template <class T, class DeAllocator = CRunTimeFree < T > >
  4494. class CAutoMemRelease
  4495. {
  4496. public:
  4497.     CAutoMemRelease()
  4498.     {
  4499.         m_pData = NULL;
  4500.     }
  4501.  
  4502.     CAutoMemRelease(T* pData)
  4503.     {
  4504.         m_pData = pData;
  4505.     }
  4506.  
  4507.     ~CAutoMemRelease()
  4508.     {
  4509.         Attach(NULL);
  4510.     }
  4511.  
  4512.     void Attach(T* pData)
  4513.     {
  4514.         DeAllocator::Free(m_pData);
  4515.         m_pData = pData;
  4516.     }
  4517.  
  4518.     T* Detach() 
  4519.     {
  4520.         T* pTemp = m_pData;
  4521.         m_pData = NULL;
  4522.         return pTemp;
  4523.     }
  4524.  
  4525.     T* m_pData;
  4526. };
  4527.  
  4528. template <class T>
  4529. class ATL_NO_VTABLE ICommandImpl : public ICommand
  4530. {
  4531. public:
  4532.     ICommandImpl() 
  4533.     {
  4534.         m_bIsExecuting = FALSE;
  4535.         m_bCancelWhenExecuting = TRUE;
  4536.         m_bCancel = FALSE;
  4537.     }
  4538.     HRESULT CancelExecution()
  4539.     {
  4540.         T* pT = (T*)this;
  4541.         pT->Lock();
  4542.         m_bCancel = TRUE;
  4543.         pT->Unlock();
  4544.         return S_OK;
  4545.     }
  4546.     STDMETHOD(Cancel)()
  4547.     {
  4548.         ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::Cancel\n");
  4549.         HRESULT hr = S_OK;
  4550.         T* pT = (T*)this;
  4551.  
  4552.         if (m_bIsExecuting && m_bCancelWhenExecuting)
  4553.         {
  4554.             hr = pT->CancelExecution();
  4555.             return hr;
  4556.         }
  4557.         if (m_bIsExecuting && !m_bCancelWhenExecuting)
  4558.             hr = DB_E_CANTCANCEL;
  4559.         return hr;
  4560.     }
  4561.     STDMETHOD(GetDBSession)(REFIID riid, IUnknown ** ppSession)
  4562.     {
  4563.         ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::GetDBSession\n");
  4564.         T* pT = (T*)this;
  4565.         ATLASSERT(pT->m_spUnkSite != NULL);
  4566.         return pT->m_spUnkSite->QueryInterface(riid, (void**) ppSession);
  4567.     }
  4568.  
  4569.     template <class RowsetClass>
  4570.     HRESULT CreateRowset(IUnknown* pUnkOuter, REFIID riid, 
  4571.                          DBPARAMS * pParams, LONG * pcRowsAffected, 
  4572.                          IUnknown** ppRowset, 
  4573.                          RowsetClass*& pRowsetObj)
  4574.     {
  4575.         HRESULT hr;
  4576.         USES_CONVERSION;
  4577.         int iBind;
  4578.         T* pT = (T*)this;
  4579.         if (ppRowset != NULL)
  4580.             *ppRowset = NULL;
  4581.         if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  4582.             return DB_E_NOAGGREGATION;
  4583.         CComPolyObject<RowsetClass>* pPolyObj; 
  4584.         if (FAILED(hr = CComPolyObject<RowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
  4585.             return hr;
  4586.         // Ref the created COM object and Auto release it on failure
  4587.         CComPtr<IUnknown> spUnk;
  4588.         hr = pPolyObj->m_contained.QueryInterface(&spUnk);
  4589.         if (FAILED(hr))
  4590.         {
  4591.             delete pPolyObj; // must hand delete as it is not ref'd
  4592.             return hr;
  4593.         }
  4594.         // Get a pointer to the Rowset instance
  4595.         pRowsetObj = &(pPolyObj->m_contained);
  4596.  
  4597.         if (FAILED(hr = pRowsetObj->FInit(pT)))
  4598.             return hr;
  4599.         pRowsetObj->SetSite(pT->GetUnknown());
  4600.  
  4601.         if (pT->m_strCommandText.Length() == 0)
  4602.         {
  4603.             ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::No command text specified.\n");
  4604.             return DB_E_NOCOMMAND;
  4605.         }
  4606.  
  4607.         pRowsetObj->m_strCommandText = pT->m_strCommandText;
  4608.         if (pRowsetObj->m_strCommandText == (BSTR)NULL)
  4609.             return E_OUTOFMEMORY;
  4610.         if (FAILED(hr = pRowsetObj->Execute(pParams, pcRowsAffected)))
  4611.             return hr;
  4612.         if (InlineIsEqualGUID(riid, IID_NULL) || ppRowset == NULL)
  4613.         {
  4614.             if (ppRowset != NULL)
  4615.                 *ppRowset = NULL;
  4616.             return hr;
  4617.         }
  4618.         hr = pPolyObj->QueryInterface(riid, (void**)ppRowset);
  4619.         if (FAILED(hr))
  4620.             return hr;
  4621.         for (iBind = 0; iBind < pT->m_rgBindings.GetSize(); iBind++)
  4622.         {
  4623.             T::_BindType* pBind = NULL;
  4624.             T::_BindType* pBindSrc = NULL;
  4625.             ATLTRY(pBind = new T::_BindType);
  4626.             if (pBind == NULL)
  4627.             {
  4628.                 ATLTRACE2(atlTraceDBProvider, 0, "Failed to allocate memory for new Binding\n");
  4629.                 return E_OUTOFMEMORY;
  4630.             }
  4631.             // auto cleanup on failure
  4632.             CAutoMemRelease<T::_BindType> amr(pBind);
  4633.             pBindSrc = pT->m_rgBindings.GetValueAt(iBind);
  4634.             if (pBindSrc == NULL)
  4635.             {
  4636.                 ATLTRACE2(atlTraceDBProvider, 0, "The map appears to be corrupted, failing!!\n");
  4637.                 return E_FAIL;
  4638.             }
  4639.             if (!pRowsetObj->m_rgBindings.Add(pT->m_rgBindings.GetKeyAt(iBind), pBind))
  4640.             {
  4641.                 ATLTRACE2(atlTraceDBProvider, 0, "Failed to add hAccessor to Map\n");
  4642.                 return E_OUTOFMEMORY;
  4643.             }
  4644.             if (pBindSrc->cBindings)
  4645.             {
  4646.                 ATLTRY(pBind->pBindings = new DBBINDING[pBindSrc->cBindings])
  4647.                 if (pBind->pBindings == NULL)
  4648.                 {
  4649.                     ATLTRACE2(atlTraceDBProvider, 0, "Failed to Allocate dbbinding Array\n");
  4650.                     // We added it, must now remove on failure
  4651.                     pRowsetObj->m_rgBindings.Remove(pT->m_rgBindings.GetKeyAt(iBind));
  4652.                     return E_OUTOFMEMORY;
  4653.                 }
  4654.             }
  4655.             else
  4656.             {
  4657.                 pBind->pBindings = NULL; // NULL Accessor
  4658.             }
  4659.  
  4660.             pBind->dwAccessorFlags = pBindSrc->dwAccessorFlags;
  4661.             pBind->cBindings = pBindSrc->cBindings;
  4662.             pBind->dwRef = 1;
  4663.             memcpy (pBind->pBindings, pBindSrc->pBindings, (pBindSrc->cBindings)*sizeof(DBBINDING));
  4664.             pBind = amr.Detach();
  4665.         }
  4666.         
  4667.         return S_OK;
  4668.     }
  4669.  
  4670.     unsigned m_bIsExecuting:1;
  4671.     unsigned m_bCancelWhenExecuting:1;
  4672.     unsigned m_bCancel:1;
  4673. };
  4674.  
  4675.  
  4676. template <class T>
  4677. class ATL_NO_VTABLE ICommandTextImpl : public ICommandImpl<T>
  4678. {
  4679. public:
  4680.     STDMETHOD(GetCommandText)(GUID * /*pguidDialect*/,LPOLESTR * ppwszCommand)
  4681.     {
  4682.         ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText\n");
  4683.         UINT cchCommandText;
  4684.         HRESULT hr = E_FAIL;
  4685.         if (ppwszCommand == NULL)
  4686.         {
  4687.             ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText Bad Command buffer\n");
  4688.             return E_INVALIDARG;
  4689.         }
  4690.         if (m_strCommandText.m_str == NULL)
  4691.         {
  4692.             ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText Bad Command buffer\n");
  4693.             return DB_E_NOCOMMAND;
  4694.         }
  4695.         cchCommandText = sizeof(OLECHAR) * (m_strCommandText.Length() + 1);
  4696.         *ppwszCommand = (OLECHAR*)CoTaskMemAlloc(cchCommandText);
  4697.         if (*ppwszCommand != NULL)
  4698.         {
  4699.             memcpy(*ppwszCommand, m_strCommandText.m_str, cchCommandText);
  4700.             *(*ppwszCommand + m_strCommandText.Length()) = (OLECHAR)NULL;
  4701.             return S_OK;
  4702.         }
  4703.         *ppwszCommand = NULL;
  4704.         return hr;
  4705.     }
  4706.  
  4707.     STDMETHOD(SetCommandText)(REFGUID /*rguidDialect*/,LPCOLESTR pwszCommand)
  4708.     {
  4709.         T* pT = (T*)this;
  4710.         ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::SetCommandText\n");
  4711.         pT->Lock();
  4712.         m_strCommandText = pwszCommand;
  4713.         pT->Unlock();
  4714.         return S_OK;
  4715.     }
  4716.  
  4717.     CComBSTR m_strCommandText;
  4718. };
  4719.  
  4720. // ISessionPropertiesImpl
  4721. template <class T, class PropClass = T>
  4722. class ATL_NO_VTABLE ISessionPropertiesImpl : 
  4723.     public ISessionProperties, 
  4724.     public CUtlProps<PropClass>
  4725. {
  4726. public:
  4727.     typedef PropClass _PropClass;
  4728.  
  4729.     STDMETHOD(GetProperties)(ULONG cPropertyIDSets,
  4730.                              const DBPROPIDSET rgPropertyIDSets[],
  4731.                              ULONG *pcPropertySets,
  4732.                              DBPROPSET **prgPropertySets)
  4733.     {
  4734.         ATLTRACE2(atlTraceDBProvider, 0, "ISessionPropertiesImpl::GetProperties\n");
  4735.         HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
  4736.         const GUID* ppGuid[1];
  4737.         ppGuid[0] = &DBPROPSET_SESSION;
  4738.  
  4739.         if(SUCCEEDED(hr))
  4740.             hr = CUtlProps<PropClass>::GetProperties(cPropertyIDSets,
  4741.                     rgPropertyIDSets, pcPropertySets, prgPropertySets, 
  4742.                     1, ppGuid);
  4743.         return hr;
  4744.  
  4745.     }
  4746.  
  4747.     STDMETHOD(SetProperties)(ULONG cPropertySets,
  4748.                              DBPROPSET rgPropertySets[])
  4749.     {
  4750.         ATLTRACE2(atlTraceDBProvider, 0, "ISessionPropertiesImpl::SetProperties");
  4751.         HRESULT hr = SetPropertiesArgChk(cPropertySets, rgPropertySets);
  4752.         const GUID* ppGuid[1];
  4753.  
  4754.         ppGuid[0] = &DBPROPSET_SESSION;
  4755.         if(SUCCEEDED(hr))
  4756.             hr = CUtlProps<PropClass>::SetProperties(0, cPropertySets, rgPropertySets,
  4757.                     1, ppGuid);
  4758.         return hr;
  4759.     }
  4760. };
  4761.  
  4762. // Implementation Class 
  4763. template <class BindType>
  4764. class ATL_NO_VTABLE IAccessorImplBase : public IAccessor
  4765. {
  4766. public:
  4767.  
  4768.     STDMETHOD(CreateAccessor)(DBACCESSORFLAGS dwAccessorFlags,
  4769.                               ULONG cBindings,
  4770.                               const DBBINDING rgBindings[],
  4771.                               ULONG /*cbRowSize*/,
  4772.                               HACCESSOR *phAccessor,
  4773.                               DBBINDSTATUS rgStatus[])
  4774.     {
  4775.         if (!(dwAccessorFlags & DBACCESSOR_PARAMETERDATA) && !(dwAccessorFlags & DBACCESSOR_ROWDATA))
  4776.             return DB_E_BADACCESSORFLAGS;
  4777.         if (dwAccessorFlags == DBACCESSOR_INVALID)
  4778.             return DB_E_BADACCESSORFLAGS;
  4779.         if (dwAccessorFlags > 0x000F)
  4780.             return DB_E_BADACCESSORFLAGS;
  4781.         BindType *pBind = NULL;
  4782.         ATLTRY(pBind = new BindType)
  4783.         if (pBind == NULL)
  4784.         {
  4785.             ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate ATL Binding struct\n"));
  4786.             return E_OUTOFMEMORY;
  4787.         }
  4788.         if (cBindings)
  4789.         {
  4790.             ATLTRY(pBind->pBindings = new DBBINDING[cBindings])
  4791.             if (pBind->pBindings == NULL)
  4792.             {
  4793.                 delete pBind;
  4794.                 return E_OUTOFMEMORY;
  4795.             }
  4796.         }
  4797.         else
  4798.             pBind->pBindings = NULL; // NULL Accessor
  4799.  
  4800.         pBind->dwAccessorFlags = dwAccessorFlags;
  4801.         pBind->cBindings = cBindings;
  4802.         pBind->dwRef = 1;
  4803.         memcpy (pBind->pBindings, rgBindings, cBindings*sizeof(DBBINDING));
  4804.         DBBINDSTATUS status = DBBINDSTATUS_OK;
  4805.         memcpy (rgStatus, &status, sizeof(DBBINDSTATUS)*cBindings);
  4806.         *phAccessor = (ULONG)pBind;
  4807.         return S_OK;
  4808.     }
  4809.     BOOL HasFlag(DBTYPE dbToCheck, DBTYPE dbCombo)
  4810.     {
  4811.         return ( (dbToCheck & dbCombo) == dbCombo );
  4812.     }
  4813.     HRESULT ValidateBindings(ULONG cBindings, const DBBINDING rgBindings[], 
  4814.                 DBBINDSTATUS rgStatus[], bool bHasBookmarks)
  4815.     {
  4816.         HRESULT hr = S_OK;;
  4817.  
  4818.         for (ULONG iBinding = 0; iBinding < cBindings; iBinding++)
  4819.         {
  4820.             const DBBINDING& rBindCur = rgBindings[iBinding];
  4821.             if (rBindCur.iOrdinal == 0)
  4822.             {
  4823.                 if (!m_bIsCommand && !bHasBookmarks)
  4824.                 {
  4825.                     hr = DB_E_ERRORSOCCURRED;
  4826.                     rgStatus[iBinding] = DBBINDSTATUS_BADORDINAL;
  4827.                     continue;
  4828.                 }
  4829.             }
  4830.             if (rBindCur.dwPart == 0) // nothing to bind to
  4831.             {
  4832.                 hr = DB_E_ERRORSOCCURRED;
  4833.                 rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4834.                 continue;
  4835.             }
  4836.             if (HasFlag(rBindCur.wType, (DBTYPE_BYREF | DBTYPE_ARRAY)))
  4837.             {
  4838.                 hr = DB_E_ERRORSOCCURRED;
  4839.                 rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4840.                 continue;
  4841.             }
  4842.             if (HasFlag(rBindCur.wType, (DBTYPE_BYREF | DBTYPE_VECTOR)))
  4843.             {
  4844.                 hr = DB_E_ERRORSOCCURRED;
  4845.                 rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4846.                 continue;
  4847.             }
  4848.             if (HasFlag(rBindCur.wType, (DBTYPE_VECTOR | DBTYPE_ARRAY)))
  4849.             {
  4850.                 hr = DB_E_ERRORSOCCURRED;
  4851.                 rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4852.                 continue;
  4853.             }
  4854.             if (rBindCur.wType == DBTYPE_NULL || rBindCur.wType == DBTYPE_EMPTY)
  4855.             {
  4856.                 hr = DB_E_ERRORSOCCURRED;
  4857.                 rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4858.                 continue;
  4859.             }
  4860.             if (HasFlag(rBindCur.wType, DBTYPE_RESERVED))
  4861.             {
  4862.                 hr = DB_E_ERRORSOCCURRED;
  4863.                 rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4864.                 continue;
  4865.             }
  4866.             // Search for DBTYPE_BYREF | DBTYPE_EMPTY
  4867.             if ((rBindCur.wType & 0xBFFF) == 0)
  4868.             {
  4869.                 hr = DB_E_ERRORSOCCURRED;
  4870.                 rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4871.                 continue;
  4872.             }
  4873.             if ((rBindCur.wType & 0xBFFE) == 0)
  4874.             {
  4875.                 hr = DB_E_ERRORSOCCURRED;
  4876.                 rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4877.                 continue;
  4878.             }
  4879.             if (rBindCur.dwMemOwner == DBMEMOWNER_PROVIDEROWNED)
  4880.             {
  4881.                 BOOL bIsPointerType = HasFlag(rBindCur.wType, DBTYPE_BYREF) ||
  4882.                                       HasFlag(rBindCur.wType, DBTYPE_VECTOR) ||
  4883.                                       HasFlag(rBindCur.wType, DBTYPE_ARRAY) ||
  4884.                                       HasFlag(~(DBTYPE_BYREF) & rBindCur.wType, DBTYPE_BSTR);
  4885.                 if (!bIsPointerType)
  4886.                 {
  4887.                     hr = DB_E_ERRORSOCCURRED;
  4888.                     rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
  4889.                     continue;
  4890.                 }
  4891.             }
  4892.  
  4893.         }
  4894.         return hr;
  4895.     }
  4896.  
  4897.     unsigned  m_bIsCommand:1;
  4898.     unsigned  m_bHasParamaters:1;
  4899.     unsigned  m_bIsChangeable:1;
  4900. };
  4901.  
  4902. // IAccessorImpl
  4903. template <class T, class BindType = ATLBINDINGS, class BindingVector = CSimpleMap < int, BindType* > >
  4904. class ATL_NO_VTABLE IAccessorImpl : public IAccessorImplBase<BindType>
  4905. {
  4906. public:
  4907.     typedef BindType _BindType;
  4908.     typedef BindingVector _BindingVector;
  4909.     IAccessorImpl()
  4910.     {
  4911.         m_bIsCommand = FALSE;
  4912.         m_bHasParamaters = FALSE;
  4913.         m_bIsChangeable = FALSE;
  4914.     }
  4915.     HRESULT FinalConstruct()
  4916.     {
  4917.         T* pT = (T*)this;
  4918.         CComQIPtr<ICommand> spCommand = pT->GetUnknown();
  4919.         if (spCommand != NULL)
  4920.         {
  4921.             m_bIsCommand = TRUE;
  4922.             CComQIPtr<ICommandWithParameters> spCommandParams = pT->GetUnknown();
  4923.             m_bHasParamaters =  spCommandParams != NULL;
  4924.         }
  4925.         else // its a Rowset
  4926.         {
  4927.             CComQIPtr<IRowsetChange> spRSChange = pT->GetUnknown();
  4928.             m_bIsChangeable = spRSChange != NULL;
  4929.         }
  4930.         return S_OK;
  4931.     }
  4932.     void FinalRelease()
  4933.     {
  4934. #ifdef _DEBUG
  4935.         if (m_rgBindings.GetSize())
  4936.             ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::~IAccessorImpl Bindings still in vector, removing\n");
  4937. #endif //_DEBUG
  4938.         while (m_rgBindings.GetSize()) 
  4939.             ReleaseAccessor((HACCESSOR)m_rgBindings.GetKeyAt(0), NULL);
  4940.     }
  4941.     STDMETHOD(AddRefAccessor)(HACCESSOR hAccessor,
  4942.                               ULONG *pcRefCount)
  4943.     {
  4944.         ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::AddRefAccessor\n");
  4945.         if (hAccessor == NULL)
  4946.         {
  4947.             ATLTRACE2(atlTraceDBProvider, 0, _T("AddRefAccessor : Bad hAccessor\n"));
  4948.             return E_INVALIDARG;
  4949.         }
  4950.         if (pcRefCount == NULL)
  4951.             pcRefCount = (ULONG*)_alloca(sizeof(ULONG));
  4952.  
  4953.         BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
  4954.         *pcRefCount = T::_ThreadModel::Increment((LONG*)&pBind->dwRef);
  4955.         return S_OK;
  4956.     }
  4957.     HRESULT ValidateBindingsFromMetaData(ULONG cBindings, const DBBINDING rgBindings[], 
  4958.                 DBBINDSTATUS rgStatus[], bool bHasBookmarks)
  4959.     {
  4960.         HRESULT hr = S_OK;
  4961.         ULONG cCols;
  4962.         // since this Fn is for Commands only (T*)this is the users Command
  4963.         ATLCOLUMNINFO* pColInfo = T::GetColumnInfo((T*)this, &cCols);
  4964.         T* pT = (T*)this;
  4965.  
  4966.         for (ULONG iBinding = 0; iBinding < cBindings; iBinding++)
  4967.         {
  4968.             const DBBINDING& rBindCur = rgBindings[iBinding];
  4969.             ULONG iOrdAdjusted;
  4970.             if (bHasBookmarks)
  4971.                 iOrdAdjusted = rBindCur.iOrdinal;    // Bookmarks start with ordinal 0
  4972.             else
  4973.                 iOrdAdjusted = rBindCur.iOrdinal - 1; // Non-bookmarks start w/ ordinal 1
  4974.             if (rBindCur.iOrdinal > cCols)
  4975.             {
  4976.                 hr = DB_E_ERRORSOCCURRED;
  4977.                 rgStatus[iBinding] = DBBINDSTATUS_BADORDINAL;
  4978.                 continue;
  4979.             }
  4980.             ATLASSERT(pT->m_spConvert != NULL);
  4981.             HRESULT hrConvert = pT->m_spConvert->CanConvert(rBindCur.wType, pColInfo[iOrdAdjusted].wType);
  4982.             if (FAILED(hrConvert) || hrConvert == S_FALSE)
  4983.             {
  4984.                 hr = DB_E_ERRORSOCCURRED;
  4985.                 rgStatus[iBinding] = DBBINDSTATUS_UNSUPPORTEDCONVERSION;
  4986.                 continue;
  4987.             }
  4988.         }
  4989.         return hr;
  4990.     }
  4991.     STDMETHOD(CreateAccessor)(DBACCESSORFLAGS dwAccessorFlags,
  4992.                               ULONG cBindings,
  4993.                               const DBBINDING rgBindings[],
  4994.                               ULONG cbRowSize,
  4995.                               HACCESSOR *phAccessor,
  4996.                               DBBINDSTATUS rgStatus[])
  4997.     {
  4998.         ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor\n");
  4999.         T* pT = (T*)this;
  5000.         CComVariant var;
  5001.  
  5002.         if (!phAccessor)
  5003.         {
  5004.             ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor : Inavlid NULL Parameter for HACCESSOR*\n");
  5005.             return E_INVALIDARG;
  5006.         }
  5007.         *phAccessor = NULL;
  5008.         if (cBindings != 0 && rgBindings == NULL)
  5009.         {
  5010.             ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor  : Bad Binding array\n");
  5011.             return E_INVALIDARG;
  5012.         }
  5013.         if (dwAccessorFlags & DBACCESSOR_PASSBYREF)
  5014.         {
  5015.             HRESULT hr = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_BYREFACCESSORS, &var);
  5016.             if (FAILED(hr) || var.boolVal == VARIANT_FALSE)
  5017.                 return DB_E_BYREFACCESSORNOTSUPPORTED;
  5018.         }
  5019.         if (!m_bHasParamaters)
  5020.         {
  5021.             if (dwAccessorFlags & DBACCESSOR_PARAMETERDATA)
  5022.                 return DB_E_BADACCESSORFLAGS;
  5023.         }
  5024.         if (m_bIsCommand || !m_bIsChangeable)
  5025.         {
  5026.             if (cBindings == 0) // No NULL Accessors on the command
  5027.                 return DB_E_NULLACCESSORNOTSUPPORTED;
  5028.         }
  5029.  
  5030.         if (rgStatus == NULL && cBindings) // Create a fake status array 
  5031.             rgStatus = (DBBINDSTATUS*)_alloca(cBindings*sizeof(DBBINDSTATUS));
  5032.  
  5033.         // Validate the Binding passed
  5034.         HRESULT hr;
  5035.         bool bHasBookmarks = false;
  5036.         HRESULT hrLocal = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_BOOKMARKS, &var);
  5037.         bHasBookmarks = (hrLocal == S_OK &&  var.boolVal == VARIANT_TRUE);
  5038.  
  5039.         hr = ValidateBindings(cBindings, rgBindings, rgStatus, bHasBookmarks);
  5040.         if (FAILED(hr))
  5041.             return hr;
  5042.         if (!m_bIsCommand)
  5043.         {
  5044.             hr = ValidateBindingsFromMetaData(cBindings, rgBindings, rgStatus, 
  5045.                     bHasBookmarks);
  5046.             if (FAILED(hr))
  5047.                 return hr;
  5048.         }
  5049.         hr = IAccessorImplBase<BindType>::CreateAccessor(dwAccessorFlags, cBindings,
  5050.             rgBindings, cbRowSize, phAccessor,rgStatus);
  5051.         if (SUCCEEDED(hr))
  5052.         {
  5053.             ATLASSERT(*phAccessor != NULL);
  5054.             pT->Lock();
  5055.             BindType* pBind = (BindType*)*phAccessor;
  5056.             hr = m_rgBindings.Add((int)pBind, pBind) ? S_OK : E_OUTOFMEMORY;
  5057.             pT->Unlock();
  5058.         }
  5059.         return hr;
  5060.     }
  5061.  
  5062.     STDMETHOD(GetBindings)(HACCESSOR hAccessor,
  5063.                            DBACCESSORFLAGS *pdwAccessorFlags,
  5064.                            ULONG *pcBindings,
  5065.                            DBBINDING **prgBindings)
  5066.     {
  5067.         ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::GetBindings");
  5068.         if (pdwAccessorFlags == NULL || pcBindings == NULL || prgBindings == NULL)
  5069.             return E_INVALIDARG;
  5070.         *prgBindings = NULL;
  5071.         BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
  5072.         HRESULT hr = DB_E_BADACCESSORHANDLE;
  5073.         if (pBind != NULL)
  5074.         {
  5075.             *pdwAccessorFlags = pBind->dwAccessorFlags;
  5076.             *pcBindings = pBind->cBindings;
  5077.             *prgBindings = (DBBINDING*)CoTaskMemAlloc(*pcBindings * sizeof(DBBINDING));
  5078.             if (*prgBindings == NULL)
  5079.                 return E_OUTOFMEMORY;
  5080.             memcpy(*prgBindings, pBind->pBindings, sizeof(DBBINDING) * (*pcBindings));
  5081.             hr = S_OK;
  5082.         }
  5083.         return hr;
  5084.     }
  5085.  
  5086.     STDMETHOD(ReleaseAccessor)(HACCESSOR hAccessor,
  5087.                                ULONG *pcRefCount)
  5088.     {
  5089.         ATLTRACE2(atlTraceDBProvider, 0, _T("IAccessorImpl::ReleaseAccessor\n"));
  5090.         BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
  5091.         if (pBind == NULL)
  5092.             return DB_E_BADACCESSORHANDLE;
  5093.  
  5094.         if (pcRefCount == NULL)
  5095.             pcRefCount = (ULONG*)_alloca(sizeof(ULONG));
  5096.         *pcRefCount = T::_ThreadModel::Decrement((LONG*)&pBind->dwRef);
  5097.         if (!(*pcRefCount))
  5098.         {
  5099.             delete [] pBind->pBindings;
  5100.             delete pBind;
  5101.             return m_rgBindings.Remove((int)hAccessor) ? S_OK : DB_E_BADACCESSORHANDLE;
  5102.         }
  5103.         return S_OK;
  5104.     }
  5105.  
  5106.     BindingVector m_rgBindings;
  5107. };
  5108.  
  5109. #define BEGIN_PROVIDER_COLUMN_MAP(theClass) \
  5110.     typedef theClass _Class; \
  5111.     template <class T> \
  5112.     static ATLCOLUMNINFO* GetColumnInfo(T* pv, ULONG* pcCols) \
  5113.     { \
  5114.     pv; \
  5115.     static ATLCOLUMNINFO _rgColumns [] = \
  5116.     {
  5117.  
  5118. #define SIZEOF_MEMBER(memberOf, member) \
  5119.     sizeof(((memberOf*)0)->member)
  5120. #define EXPANDGUID(guid) \
  5121.     { guid.Data1, guid.Data2, guid.Data3, \
  5122.     { guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] } }
  5123.  
  5124. #define PROVIDER_COLUMN_ENTRY_GN(name, ordinal, flags, colSize, dbtype, precision, scale, guid) \
  5125. { (LPOLESTR)name, (ITypeInfo*)NULL, (ULONG)ordinal, (DBCOLUMNFLAGS)flags, (ULONG)colSize, (DBTYPE)dbtype, (BYTE)precision, (BYTE)scale, { EXPANDGUID(guid), (DWORD)0, (LPOLESTR) name}, 0},
  5126.  
  5127. #define PROVIDER_COLUMN_ENTRY(name, ordinal, member) \
  5128.     { \
  5129.         (LPOLESTR)OLESTR(name), \
  5130.         (ITypeInfo*)NULL, \
  5131.         (ULONG)ordinal, \
  5132.         DBCOLUMNFLAGS_ISFIXEDLENGTH, \
  5133.         (ULONG)sizeof(((_Class*)0)->member), \
  5134.         _GetOleDBType(((_Class*)0)->member), \
  5135.         (BYTE)0, \
  5136.         (BYTE)0, \
  5137.         { \
  5138.             EXPANDGUID(GUID_NULL), \
  5139.             (DWORD)0, \
  5140.             (LPOLESTR) name \
  5141.         }, \
  5142.         offsetof(_Class, member) \
  5143.     },
  5144.  
  5145. #define PROVIDER_COLUMN_ENTRY_LENGTH(name, ordinal, size, member) \
  5146.     { \
  5147.         (LPOLESTR)OLESTR(name), \
  5148.         (ITypeInfo*)NULL, \
  5149.         (ULONG)ordinal, \
  5150.         DBCOLUMNFLAGS_ISFIXEDLENGTH, \
  5151.         (ULONG)size, \
  5152.         _GetOleDBType(((_Class*)0)->member), \
  5153.         (BYTE)0, \
  5154.         (BYTE)0, \
  5155.         { \
  5156.             EXPANDGUID(GUID_NULL), \
  5157.             (DWORD)0, \
  5158.             (LPOLESTR) name \
  5159.         }, \
  5160.         offsetof(_Class, member) \
  5161.     },
  5162.  
  5163. #define PROVIDER_COLUMN_ENTRY_FIXED(name, ordinal, dbtype, member) \
  5164.     { \
  5165.         (LPOLESTR)OLESTR(name), \
  5166.         (ITypeInfo*)NULL, \
  5167.         (ULONG)ordinal, \
  5168.         DBCOLUMNFLAGS_ISFIXEDLENGTH, \
  5169.         (ULONG)sizeof(((_Class*)0)->member), \
  5170.         (DBTYPE)dbtype, \
  5171.         (BYTE)0, \
  5172.         (BYTE)0, \
  5173.         { \
  5174.             EXPANDGUID(GUID_NULL), \
  5175.             (DWORD)0, \
  5176.             (LPOLESTR) name \
  5177.         }, \
  5178.         offsetof(_Class, member) \
  5179.     },
  5180.  
  5181. #define PROVIDER_COLUMN_ENTRY_STR(name, ordinal, member) \
  5182.     { \
  5183.         (LPOLESTR)OLESTR(name), \
  5184.         (ITypeInfo*)NULL, \
  5185.         (ULONG)ordinal, \
  5186.         0, \
  5187.         (ULONG)sizeof(((_Class*)0)->member), \
  5188.         DBTYPE_STR, \
  5189.         (BYTE)0xFF, \
  5190.         (BYTE)0xFF, \
  5191.         { \
  5192.             EXPANDGUID(GUID_NULL), \
  5193.             (DWORD)0, \
  5194.             (LPOLESTR) name \
  5195.         }, \
  5196.         offsetof(_Class, member) \
  5197.     },
  5198.  
  5199. #define PROVIDER_COLUMN_ENTRY_WSTR(name, ordinal, member) \
  5200.     { \
  5201.         (LPOLESTR)OLESTR(name), \
  5202.         (ITypeInfo*)NULL, \
  5203.         (ULONG)ordinal, \
  5204.         0, \
  5205.         (ULONG)sizeof(((_Class*)0)->member), \
  5206.         DBTYPE_WSTR, \
  5207.         (BYTE)0xFF, \
  5208.         (BYTE)0xFF, \
  5209.         { \
  5210.             EXPANDGUID(GUID_NULL), \
  5211.             (DWORD)0, \
  5212.             (LPOLESTR) name \
  5213.         }, \
  5214.         offsetof(_Class, member) \
  5215.     },
  5216.  
  5217. #define END_PROVIDER_COLUMN_MAP() \
  5218. }; *pcCols = sizeof(_rgColumns)/sizeof(ATLCOLUMNINFO); return _rgColumns;}
  5219.  
  5220. // Implementation Class 
  5221. class CSimpleRow
  5222. {
  5223. public:
  5224.     typedef LONG KeyType;
  5225.  
  5226.     CSimpleRow(LONG iRowsetCur) 
  5227.     { 
  5228.         m_dwRef = 0;
  5229.         m_iRowset = iRowsetCur; 
  5230.         m_pMem = NULL;
  5231.     }
  5232.     ~CSimpleRow()
  5233.     {
  5234.         if (m_pMem != NULL)
  5235.             ::CoTaskMemFree(m_pMem);
  5236.     }
  5237.     DWORD AddRefRow() { return CComObjectThreadModel::Increment((LPLONG)&m_dwRef); } 
  5238.     DWORD ReleaseRow() { return CComObjectThreadModel::Decrement((LPLONG)&m_dwRef); }
  5239.  
  5240.     HRESULT Compare(CSimpleRow* pRow)
  5241.     {
  5242.         ATLASSERT(pRow != NULL);
  5243.         return (m_iRowset == pRow->m_iRowset) ? S_OK : S_FALSE;
  5244.     }
  5245.  
  5246.     KeyType m_iRowset;
  5247.     DWORD    m_dwRef;
  5248.     void*    m_pMem;
  5249. };
  5250.  
  5251. // IRowsetImpl
  5252. template <class T, class RowClass = CSimpleRow, class MapClass = CSimpleMap < RowClass::KeyType, RowClass* > >
  5253. class ATL_NO_VTABLE IRowsetImpl : public IRowset
  5254. {
  5255. public:
  5256.     typedef RowClass _HRowClass;
  5257.     IRowsetImpl()
  5258.     {
  5259.         m_iRowset = 0;
  5260.         m_bCanScrollBack = false;
  5261.         m_bCanFetchBack = false;
  5262.         m_bReset = true;
  5263.     }
  5264.     HRESULT RefRows(ULONG cRows, const HROW rghRows[], ULONG rgRefCounts[],
  5265.                     DBROWSTATUS rgRowStatus[], BOOL bAdd)
  5266.     {
  5267.         ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::AddRefRows\n");
  5268.         if (rghRows == NULL)
  5269.             return E_INVALIDARG;
  5270.         if (cRows == 0)
  5271.             return S_OK;
  5272.         T::ObjectLock cab((T*)this);
  5273.         BOOL bSuccess1 = FALSE;
  5274.         BOOL bFailed1 = FALSE;
  5275.         DBROWSTATUS rs;
  5276.         DWORD dwRef;
  5277.         for (ULONG iRow = 0; iRow < cRows; iRow++)
  5278.         {
  5279.             HROW hRowCur = rghRows[iRow];
  5280.             RowClass* pRow = m_rgRowHandles.Lookup((RowClass::KeyType)hRowCur);
  5281.             if (pRow == NULL)
  5282.             {
  5283.                 ATLTRACE2(atlTraceDBProvider, 0, "Could not find HANDLE %x in list\n");
  5284.                 rs = DBROWSTATUS_E_INVALID;
  5285.                 dwRef = 0;
  5286.                 bFailed1 = TRUE;
  5287.             }
  5288.             else
  5289.             {
  5290.                 dwRef = pRow->AddRefRow();
  5291.                 if (bAdd)
  5292.                     dwRef = pRow->AddRefRow();
  5293.                 else
  5294.                 {
  5295.                     dwRef = pRow->ReleaseRow();
  5296.                     if (dwRef == 0)
  5297.                     {
  5298.                         delete pRow;
  5299.                         m_rgRowHandles.Remove((RowClass::KeyType)hRowCur);
  5300.                     }
  5301.                 }
  5302.                 bSuccess1 = TRUE;
  5303.                 rs = DBROWSTATUS_S_OK;
  5304.             }
  5305.             if (rgRefCounts)
  5306.                 rgRefCounts[iRow] = dwRef;
  5307.             if (rgRowStatus != NULL)
  5308.                 rgRowStatus[iRow] = rs;
  5309.         }
  5310.         if (!bSuccess1 && !bFailed1)
  5311.         {
  5312.             ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::RefRows Unexpected state\n");
  5313.             return E_FAIL;
  5314.         }
  5315.         HRESULT hr = S_OK;
  5316.         if (bSuccess1 && bFailed1)
  5317.             hr = DB_S_ERRORSOCCURRED;
  5318.         if (!bSuccess1 && bFailed1)
  5319.             hr = DB_E_ERRORSOCCURRED;
  5320.         return hr;
  5321.     }
  5322.  
  5323.     STDMETHOD(AddRefRows)(ULONG cRows,
  5324.                           const HROW rghRows[],
  5325.                           ULONG rgRefCounts[],
  5326.                           DBROWSTATUS rgRowStatus[])
  5327.     {
  5328.         ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::AddRefRows\n");
  5329.         if (cRows == 0)
  5330.             return S_OK;
  5331.         return RefRows(cRows, rghRows, rgRefCounts, rgRowStatus, TRUE);
  5332.     }
  5333.     DBSTATUS GetDBStatus(RowClass* , HACCESSOR)
  5334.     {
  5335.         return DBSTATUS_S_OK;
  5336.     }
  5337.     STDMETHOD(GetData)(HROW hRow,
  5338.                        HACCESSOR hAccessor,
  5339.                        void *pDstData)
  5340.     {
  5341.         ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::GetData\n");
  5342.         if (pDstData == NULL)
  5343.             return E_INVALIDARG;
  5344.         HRESULT hr = S_OK;
  5345.         RowClass* pRow = (RowClass*)hRow;
  5346.         if (hRow == NULL || (pRow = m_rgRowHandles.Lookup((RowClass::KeyType)hRow)) == NULL)
  5347.             return DB_E_BADROWHANDLE;
  5348.         T* pT = (T*) this;
  5349.         T::_BindType* pBinding = pT->m_rgBindings.Lookup((int)hAccessor);
  5350.         if (pBinding == NULL)
  5351.             return DB_E_BADACCESSORHANDLE;
  5352.         void* pSrcData;
  5353.         pSrcData = (void*)&(pT->m_rgRowData[pRow->m_iRowset]);
  5354.         ULONG cCols;
  5355.         ATLCOLUMNINFO* pColInfo = T::GetColumnInfo((T*)this, &cCols);
  5356.         for (ULONG iBind =0; iBind < pBinding->cBindings; iBind++)
  5357.         {
  5358.             DBBINDING* pBindCur = &(pBinding->pBindings[iBind]);
  5359.             for (ULONG iColInfo = 0; 
  5360.                  iColInfo < cCols && pBindCur->iOrdinal != pColInfo[iColInfo].iOrdinal;
  5361.                  iColInfo++);
  5362.             if (iColInfo == cCols)
  5363.                 return DB_E_BADORDINAL;
  5364.             ATLCOLUMNINFO* pColCur = &(pColInfo[iColInfo]);
  5365.             // Ordinal found at iColInfo
  5366.             BOOL bProvOwn = pBindCur->dwMemOwner == DBMEMOWNER_PROVIDEROWNED;
  5367.             bProvOwn;
  5368.             DBSTATUS dbStat = pT->GetDBStatus(pRow, hAccessor);
  5369.             ULONG cbDst = pBindCur->cbMaxLen;
  5370.             ULONG cbCol = pColCur->ulColumnSize;
  5371.             ATLASSERT(pT->m_spConvert != NULL);
  5372.             BYTE* pSrcTemp;
  5373.  
  5374.             if (bProvOwn && pColCur->wType == pBindCur->wType)
  5375.             {
  5376.                 pSrcTemp = ((BYTE*)(pSrcData) + pColCur->cbOffset);
  5377.             }
  5378.             else
  5379.             {
  5380.                 BYTE* pDstTemp = (BYTE*)pDstData + pBindCur->obValue;
  5381.                 switch (pColCur->wType)
  5382.                 {
  5383.                 case DBTYPE_STR:
  5384.                     cbCol = lstrlenA((LPSTR)(((BYTE*)pSrcData) + pColCur->cbOffset));
  5385.                     break;
  5386.                 case DBTYPE_WSTR:
  5387.                 case DBTYPE_BSTR:
  5388.                     cbCol = lstrlenW((LPWSTR)(((BYTE*)pSrcData) + pColCur->cbOffset)) * sizeof(WCHAR);
  5389.                     break;
  5390.                 default:
  5391.                     cbCol = pColCur->ulColumnSize;
  5392.                     break;
  5393.                 }
  5394.                 if (pBindCur->dwPart & DBPART_VALUE)
  5395.                 {
  5396.                     hr = pT->m_spConvert->DataConvert(pColCur->wType, pBindCur->wType, 
  5397.                                             cbCol, &cbDst, (BYTE*)(pSrcData) + pColCur->cbOffset,
  5398.                                             pDstTemp, pBindCur->cbMaxLen, dbStat, &dbStat, 
  5399.                                             pBindCur->bPrecision, pBindCur->bScale,0);
  5400.                     if (SUCCEEDED(hr) && bProvOwn) 
  5401.                         pRow->m_pMem = pDstTemp;
  5402.                 }
  5403.             }
  5404.             if (pBindCur->dwPart & DBPART_LENGTH)
  5405.                 *((ULONG*)((BYTE*)(pDstData) + pBindCur->obLength)) = cbDst;
  5406.             if (pBindCur->dwPart & DBPART_STATUS)
  5407.                 *((DBSTATUS*)((BYTE*)(pDstData) + pBindCur->obStatus)) = dbStat; 
  5408.             if (FAILED(hr))
  5409.                 return hr;
  5410.         }
  5411.         return hr;
  5412.     }
  5413.  
  5414.     HRESULT CreateRow(LONG lRowsOffset, ULONG& cRowsObtained, HROW* rgRows)
  5415.     {
  5416.         RowClass* pRow = NULL;
  5417.         ATLASSERT(lRowsOffset >= 0);
  5418.         RowClass::KeyType key = lRowsOffset+1;
  5419.         ATLASSERT(key > 0);
  5420.         pRow = m_rgRowHandles.Lookup(key);
  5421.         if (pRow == NULL)
  5422.         {
  5423.             ATLTRY(pRow = new RowClass(lRowsOffset))
  5424.             if (pRow == NULL)
  5425.                 return E_OUTOFMEMORY;
  5426.             if (!m_rgRowHandles.Add(key, pRow))
  5427.                 return E_OUTOFMEMORY;
  5428.         }
  5429.         pRow->AddRefRow();
  5430.         m_bReset = false;
  5431.         rgRows[cRowsObtained++] = (HROW)key;
  5432.         return S_OK;
  5433.     }
  5434.  
  5435.     STDMETHOD(GetNextRows)(HCHAPTER /*hReserved*/,
  5436.                            LONG lRowsOffset,
  5437.                            LONG cRows,
  5438.                            ULONG *pcRowsObtained,
  5439.                            HROW **prghRows)
  5440.     {
  5441.         LONG lTmpRows = lRowsOffset;
  5442.         ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::GetNextRows\n");
  5443.         if (pcRowsObtained != NULL)
  5444.             *pcRowsObtained = 0;
  5445.         if (cRows == 0 && prghRows != NULL)
  5446.             *prghRows = NULL;
  5447.         if (prghRows == NULL || pcRowsObtained == NULL)
  5448.             return E_INVALIDARG;
  5449.         if (cRows == 0)
  5450.             return S_OK;
  5451.         HRESULT hr = S_OK;
  5452.         T* pT = (T*) this;
  5453.         T::ObjectLock cab(pT);
  5454.         if (lRowsOffset < 0 && !m_bCanScrollBack)
  5455.             return DB_E_CANTSCROLLBACKWARDS;
  5456.         if (cRows < 0  && !m_bCanFetchBack)
  5457.             return DB_E_CANTFETCHBACKWARDS;
  5458.  
  5459.         // Calculate # of rows in set and the base fetch position.  If the rowset
  5460.         // is at its head position, then lRowOffset < 0 means moving from the BACK 
  5461.         // of the rowset and not the front.
  5462.         LONG cRowsInSet = ((T*)this)->m_rgRowData.GetSize();
  5463.         if (((lRowsOffset == LONG_MIN) && (cRowsInSet != LONG_MIN))
  5464.             || (abs(lRowsOffset)) > cRowsInSet ||
  5465.             (abs(lRowsOffset) == cRowsInSet && lRowsOffset < 0 && cRows < 0) ||
  5466.             (abs(lRowsOffset) == cRowsInSet && lRowsOffset > 0 && cRows > 0))
  5467.             return DB_E_BADSTARTPOSITION;
  5468.  
  5469.         // In the case where the user is moving backwards after moving forwards,
  5470.         // we do not wrap around to the end of the rowset.
  5471.         if ((m_iRowset == 0 && !m_bReset && cRows < 0) ||
  5472.             (((LONG)m_iRowset + lRowsOffset) > cRowsInSet) ||
  5473.             (m_iRowset == (DWORD)cRowsInSet && lRowsOffset >= 0 && cRows > 0))
  5474.             return DB_S_ENDOFROWSET;
  5475.  
  5476.         // Note, if m_bReset, m_iRowset must be 0
  5477.         if (lRowsOffset < 0 && m_bReset)
  5478.         {
  5479.             ATLASSERT(m_iRowset == 0);
  5480.             m_iRowset = cRowsInSet;
  5481.         }
  5482.  
  5483.         int iStepSize = cRows >= 0 ? 1 : -1;
  5484.  
  5485.         // If cRows == LONG_MIN, we can't use ABS on it.  Therefore, we reset it
  5486.         // to a value just greater than cRowsInSet
  5487.         if (cRows == LONG_MIN && cRowsInSet != LONG_MIN)
  5488.             cRows = cRowsInSet + 2;    // set the value to something we can deal with
  5489.         else
  5490.             cRows = abs(cRows);
  5491.  
  5492.         if (iStepSize < 0 && m_iRowset == 0 && m_bReset && lRowsOffset <= 0)
  5493.             m_iRowset = cRowsInSet;
  5494.  
  5495.         lRowsOffset += m_iRowset;
  5496.         
  5497.         *pcRowsObtained = 0;
  5498.         CAutoMemRelease<HROW, CComFree< HROW > > amr;
  5499.         if (*prghRows == NULL)
  5500.         {
  5501.             int cHandlesToAlloc = (cRows > cRowsInSet) ? cRowsInSet : cRows;
  5502.             if (iStepSize == 1 && (cRowsInSet - lRowsOffset) < cHandlesToAlloc)
  5503.                 cHandlesToAlloc = cRowsInSet - lRowsOffset;
  5504.             if (iStepSize == -1 && lRowsOffset < cHandlesToAlloc)
  5505.                 cHandlesToAlloc = lRowsOffset;
  5506.             *prghRows = (HROW*)CoTaskMemAlloc((cHandlesToAlloc) * sizeof(HROW*));
  5507.             amr.Attach(*prghRows);
  5508.         }
  5509.         if (*prghRows == NULL)
  5510.             return E_OUTOFMEMORY;
  5511.         while ((lRowsOffset >= 0 && cRows != 0) &&
  5512.             ((lRowsOffset < cRowsInSet) || (lRowsOffset <= cRowsInSet && iStepSize < 0))) 
  5513.         {
  5514.             // cRows > cRowsInSet && iStepSize < 0
  5515.             if (lRowsOffset == 0 && cRows > 0 && iStepSize < 0)
  5516.                 break;
  5517.  
  5518.             // in the case where we have iStepSize < 0, move the row back
  5519.             // further because we want the previous row
  5520.             LONG lRow = lRowsOffset;
  5521.             if ((lRowsOffset == 0) && (lTmpRows == 0) && (iStepSize < 0))
  5522.                 lRow = cRowsInSet;
  5523.  
  5524.             if (iStepSize < 0)
  5525.                 lRow += iStepSize;
  5526.  
  5527.             hr = pT->CreateRow(lRow, *pcRowsObtained, *prghRows);
  5528.             if (FAILED(hr))
  5529.             {
  5530.                 for (ULONG iRowDel = 0; iRowDel < *pcRowsObtained; iRowDel++)
  5531.                 {
  5532.                     delete (RowClass*)(*prghRows[iRowDel]);
  5533.                     *prghRows[iRowDel] = NULL;
  5534.                 }
  5535.                 *pcRowsObtained = 0; 
  5536.                 return hr;
  5537.             }
  5538.             cRows--;
  5539.             lRowsOffset += iStepSize;
  5540.         }
  5541.  
  5542.         if ((lRowsOffset >= cRowsInSet && cRows) || (lRowsOffset < 0 && cRows)    ||
  5543.             (lRowsOffset == 0 && cRows > 0 && iStepSize < 0))
  5544.             hr = DB_S_ENDOFROWSET;
  5545.         m_iRowset = lRowsOffset;
  5546.         if (SUCCEEDED(hr))
  5547.             amr.Detach();
  5548.         return hr;
  5549.     }
  5550.  
  5551.     STDMETHOD(ReleaseRows)(ULONG cRows,
  5552.                            const HROW rghRows[],
  5553.                            DBROWOPTIONS rgRowOptions[],
  5554.                            ULONG rgRefCounts[],
  5555.                            DBROWSTATUS rgRowStatus[])
  5556.     {
  5557.         ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::ReleaseRows\n");
  5558.         if (cRows == 0)
  5559.             return S_OK;
  5560.         rgRowOptions;
  5561.         return RefRows(cRows, rghRows, rgRefCounts, rgRowStatus, FALSE);
  5562.     }
  5563.  
  5564.     STDMETHOD(RestartPosition)(HCHAPTER /*hReserved*/)
  5565.     {
  5566.         ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::RestartPosition\n");
  5567.         m_iRowset = 0;
  5568.         m_bReset = true;
  5569.         return S_OK;
  5570.     }
  5571.  
  5572.     MapClass  m_rgRowHandles;
  5573.     DWORD      m_iRowset; // cursor
  5574.     unsigned  m_bCanScrollBack:1;
  5575.     unsigned  m_bCanFetchBack:1;
  5576.     unsigned  m_bReset:1;
  5577. };
  5578.  
  5579. ///////////////////////////////////////////////////////////////////////////
  5580. // IRowsetIdentityImpl 
  5581. template <class T, class RowClass = CSimpleRow>
  5582. class ATL_NO_VTABLE IRowsetIdentityImpl : public IRowsetIdentity
  5583. {
  5584. public:
  5585.     STDMETHOD(IsSameRow)(HROW hThisRow, HROW hThatRow)
  5586.     {
  5587.         ATLTRACE2(atlTraceDBProvider, 0, _T("IRowsetIdentityImpl::IsSameRow"));        
  5588.         T* pT = (T*)this;
  5589.  
  5590.         // Validate row handles
  5591.         RowClass* pRow1 = pT->m_rgRowHandles.Lookup((RowClass::KeyType)hThisRow);
  5592.         RowClass* pRow2 = pT->m_rgRowHandles.Lookup((RowClass::KeyType)hThatRow);
  5593.  
  5594.         if (pRow1 == NULL || pRow2 == NULL)
  5595.             return DB_E_BADROWHANDLE;
  5596.  
  5597.         return pRow1->Compare(pRow2);
  5598.     };
  5599. };
  5600.  
  5601. template <class T>
  5602. class ATL_NO_VTABLE IInternalConnectionImpl : public IInternalConnection
  5603. {
  5604. public:
  5605.     STDMETHOD(AddConnection)()
  5606.     {
  5607.         T* pT = (T*)this;
  5608.         T::_ThreadModel::Increment(&pT->m_cSessionsOpen);
  5609.         return S_OK;
  5610.     }
  5611.     STDMETHOD(ReleaseConnection)()
  5612.     {
  5613.         T* pT = (T*)this;
  5614.         T::_ThreadModel::Decrement(&pT->m_cSessionsOpen);
  5615.         return S_OK;
  5616.     }
  5617. };
  5618.  
  5619. template <class T>
  5620. class ATL_NO_VTABLE IObjectWithSiteSessionImpl : public IObjectWithSiteImpl< T > 
  5621. {
  5622. public:
  5623.     
  5624.     ~IObjectWithSiteSessionImpl()
  5625.     {
  5626.         CComPtr<IInternalConnection> pConn;
  5627.         if (m_spUnkSite != NULL)
  5628.         {
  5629.             if (SUCCEEDED(m_spUnkSite->QueryInterface(IID_IInternalConnection, (void**)&pConn)))
  5630.                 pConn->ReleaseConnection();
  5631.         }
  5632.     }
  5633.     STDMETHOD(SetSite)(IUnknown* pCreator)
  5634.     {
  5635.         HRESULT hr = S_OK;
  5636.         T* pT = (T*)this;
  5637.         pT->Lock();
  5638.         m_spUnkSite = pCreator;
  5639.         pT->Unlock();
  5640.         CComPtr<IInternalConnection> pConn;
  5641.         if (pCreator != NULL)
  5642.         {
  5643.             hr = pCreator->QueryInterface(IID_IInternalConnection, (void**)&pConn);
  5644.             if (SUCCEEDED(hr))
  5645.                 hr = pConn->AddConnection();
  5646.         }
  5647.         return hr;
  5648.     }
  5649. };
  5650.  
  5651. template <class T>
  5652. class ATL_NO_VTABLE IRowsetCreatorImpl : public IObjectWithSiteImpl< T >
  5653. {
  5654. public:
  5655.  
  5656.     STDMETHOD(SetSite)(IUnknown* pCreator)
  5657.     {
  5658.         T* pT = (T*)this;
  5659.         HRESULT hr = S_OK;
  5660.         pT->Lock();
  5661.         m_spUnkSite = pCreator;
  5662.         pT->Unlock();
  5663.         CComVariant varPropScroll, varPropFetch;
  5664.         HRESULT hrProps = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_CANSCROLLBACKWARDS, &varPropScroll);
  5665.         if (SUCCEEDED(hrProps))
  5666.             pT->m_bCanScrollBack = varPropScroll.boolVal == VARIANT_TRUE;
  5667.         hrProps = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_CANFETCHBACKWARDS, &varPropFetch);
  5668.         if (SUCCEEDED(hrProps))
  5669.             pT->m_bCanFetchBack = (varPropFetch.boolVal == VARIANT_TRUE);
  5670.         return hr;
  5671.     }
  5672.  
  5673. };
  5674.  
  5675. // IRowsetInfoImpl
  5676. template <class T, class PropClass = T>
  5677. class ATL_NO_VTABLE IRowsetInfoImpl : 
  5678.     public IRowsetInfo, 
  5679.     public CUtlProps<PropClass>
  5680. {
  5681. public:
  5682.     static UPROPSET* _GetPropSet(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet = NULL, GUID* pguidSet = (GUID*)&(GUID_NULL))
  5683.     {
  5684.         return PropClass::_GetPropSet(pNumPropSets, pcElemPerSupported, pSet, pguidSet);
  5685.     }
  5686.     STDMETHOD(GetProperties)(const ULONG cPropertyIDSets,
  5687.                              const DBPROPIDSET rgPropertyIDSets[],
  5688.                              ULONG *pcPropertySets,
  5689.                              DBPROPSET **prgPropertySets)
  5690.     {
  5691.         ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetProperties\n");
  5692.         HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
  5693.         const GUID* ppGuid[1];
  5694.         ppGuid[0] = &DBPROPSET_ROWSET;
  5695.         if(SUCCEEDED(hr))
  5696.             return CUtlProps<PropClass>::GetProperties(cPropertyIDSets, 
  5697.                     rgPropertyIDSets, pcPropertySets, prgPropertySets, 
  5698.                     1, ppGuid);
  5699.         else
  5700.             return hr;
  5701.     }
  5702.  
  5703.     STDMETHOD(GetReferencedRowset)(ULONG iOrdinal,
  5704.                                    REFIID riid,
  5705.                                    IUnknown **ppReferencedRowset)
  5706.     {
  5707.         ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetReferencedRowset\n");
  5708.         ULONG cCols=0;
  5709.  
  5710.         // Check Arguments
  5711.         if( ppReferencedRowset == NULL )
  5712.         {
  5713.             ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetReferencedRowset : Error NULL IUnk output Param\n");
  5714.             return E_INVALIDARG;
  5715.         }
  5716.         *ppReferencedRowset = NULL;
  5717.  
  5718.         // Check to see if column in question is a bookmark
  5719.         ATLCOLUMNINFO* pColInfo = T::GetColumnInfo((T*)this, &cCols);
  5720.  
  5721.         for (ULONG iColInfo = 0; 
  5722.              iColInfo < cCols && iOrdinal != pColInfo[iColInfo].iOrdinal;
  5723.              iColInfo++);
  5724.         if (iColInfo == cCols)
  5725.             return DB_E_BADORDINAL;
  5726.         ATLCOLUMNINFO* pColCur = &(pColInfo[iColInfo]);
  5727.  
  5728.         if ((pColCur->dwFlags && DBCOLUMNFLAGS_ISBOOKMARK) == 0)
  5729.             return DB_E_NOTAREFERENCECOLUMN;
  5730.  
  5731.         // Query for requested interface
  5732.         return QueryInterface(riid, (void**)ppReferencedRowset);
  5733.     }
  5734.  
  5735.     STDMETHOD(GetSpecification)(REFIID riid,
  5736.                                 IUnknown **ppSpecification)
  5737.     {
  5738.         ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetSpecification\n");
  5739.         if (ppSpecification == NULL)
  5740.             return E_INVALIDARG;
  5741.         T* pT = (T*) this;
  5742.         T::ObjectLock cab(pT);
  5743.         ATLASSERT(pT->m_spUnkSite != NULL);
  5744.         return pT->m_spUnkSite->QueryInterface(riid, (void**)ppSpecification);
  5745.     }
  5746. };
  5747.  
  5748.  
  5749. template <class T, class Storage, class CreatorClass, class ArrayType = CSimpleArray<Storage> >
  5750. class CRowsetBaseImpl : 
  5751. public CComObjectRootEx<CreatorClass::_ThreadModel>,
  5752.     public IAccessorImpl<T>,
  5753.     public IRowsetIdentityImpl<T>,
  5754.     public IRowsetCreatorImpl<T>,
  5755.     public IRowsetInfoImpl<T, CreatorClass::_PropClass>,
  5756.     public IColumnsInfoImpl<T>,
  5757.     public IConvertTypeImpl<T>
  5758. {
  5759. public:
  5760.  
  5761.     typedef CreatorClass _RowsetCreatorClass;
  5762.     typedef ArrayType _RowsetArrayType;
  5763.  
  5764. BEGIN_COM_MAP(CRowsetBaseImpl)
  5765.     COM_INTERFACE_ENTRY(IAccessor)
  5766.     COM_INTERFACE_ENTRY(IObjectWithSite)
  5767.     COM_INTERFACE_ENTRY(IRowsetInfo)
  5768.     COM_INTERFACE_ENTRY(IColumnsInfo)
  5769.     COM_INTERFACE_ENTRY(IConvertType)
  5770.     COM_INTERFACE_ENTRY(IRowsetIdentity)
  5771. END_COM_MAP()
  5772.  
  5773.     HRESULT FinalConstruct()
  5774.     {
  5775.         HRESULT hr = FInit();
  5776.         if (FAILED(hr))
  5777.             return hr;
  5778.         hr = IAccessorImpl<T>::FinalConstruct();
  5779.         if (FAILED(hr))
  5780.             return hr;
  5781.         return CConvertHelper::FinalConstruct();
  5782.     }
  5783.  
  5784.     HRESULT NameFromDBID(DBID* pDBID, CComBSTR& bstr, bool bIndex)
  5785.     {
  5786.  
  5787.         if (pDBID->uName.pwszName != NULL)
  5788.         {
  5789.             bstr = pDBID->uName.pwszName;
  5790.             if (m_strCommandText == (BSTR)NULL)
  5791.                 return E_OUTOFMEMORY;
  5792.             return S_OK;
  5793.         }
  5794.  
  5795.         return (bIndex) ? DB_E_NOINDEX : DB_E_NOTABLE;
  5796.     }
  5797.     
  5798.     HRESULT GetCommandFromID(DBID* pTableID, DBID* pIndexID)
  5799.     {
  5800.         USES_CONVERSION;
  5801.         HRESULT hr;
  5802.  
  5803.         if (pTableID == NULL && pIndexID == NULL)
  5804.             return E_INVALIDARG;
  5805.  
  5806.         if (pTableID != NULL && pTableID->eKind == DBKIND_NAME)
  5807.         {
  5808.             hr = NameFromDBID(pTableID, m_strCommandText, true);
  5809.             if (FAILED(hr))
  5810.                 return hr;
  5811.             if (pIndexID != NULL)
  5812.             {
  5813.                 if (pIndexID->eKind == DBKIND_NAME)
  5814.                 {
  5815.                     hr = NameFromDBID(pIndexID, m_strIndexText, false);
  5816.                     if (FAILED(hr))
  5817.                     {
  5818.                         m_strCommandText.Empty();
  5819.                         return hr;
  5820.                     }
  5821.                 }
  5822.                 else
  5823.                 {
  5824.                     m_strCommandText.Empty();
  5825.                     return DB_E_NOINDEX;
  5826.                 }
  5827.             }
  5828.             return S_OK;
  5829.         }
  5830.         if (pIndexID != NULL && pIndexID->eKind == DBKIND_NAME)
  5831.             return NameFromDBID(pIndexID, m_strIndexText, false);
  5832.  
  5833.         return S_OK;
  5834.     }
  5835.  
  5836.     HRESULT ValidateCommandID(DBID* pTableID, DBID* pIndexID)
  5837.     {
  5838.         HRESULT hr = S_OK;
  5839.         
  5840.         if (pTableID != NULL)
  5841.         {
  5842.             hr = CUtlProps<T>::IsValidDBID(pTableID);
  5843.  
  5844.             if (hr != S_OK)
  5845.                 return hr;
  5846.  
  5847.             // Check for a NULL TABLE ID (where its a valid pointer but NULL)
  5848.             if ((pTableID->eKind == DBKIND_GUID_NAME || 
  5849.                 pTableID->eKind == DBKIND_NAME ||
  5850.                 pTableID->eKind == DBKIND_PGUID_NAME)
  5851.                 && pTableID->uName.pwszName == NULL)
  5852.                 return DB_E_NOTABLE;
  5853.         }
  5854.  
  5855.         if (pIndexID != NULL)
  5856.             hr = CUtlProps<T>::IsValidDBID(pIndexID);
  5857.  
  5858.         return hr;
  5859.     }
  5860.  
  5861.     HRESULT SetCommandText(DBID* pTableID, DBID* pIndexID)
  5862.     {
  5863.         T* pT = (T*)this;
  5864.         HRESULT hr = pT->ValidateCommandID(pTableID, pIndexID);
  5865.         if (FAILED(hr))
  5866.             return hr;
  5867.         hr = pT->GetCommandFromID(pTableID, pIndexID);
  5868.         return hr;
  5869.     }
  5870.     void FinalRelease()
  5871.     {
  5872.         m_rgRowData.RemoveAll();
  5873.     }
  5874.  
  5875.     static ATLCOLUMNINFO* GetColumnInfo(T* pv, ULONG* pcCols)
  5876.     {
  5877.         return Storage::GetColumnInfo(pv,pcCols);
  5878.     }
  5879.  
  5880.  
  5881.     CComBSTR m_strCommandText;
  5882.     CComBSTR m_strIndexText;
  5883.     ArrayType m_rgRowData;
  5884. };
  5885.  
  5886.  
  5887. template <class T, class Storage, class CreatorClass, class ArrayType = CSimpleArray<Storage> >
  5888. class CRowsetImpl:
  5889.     public CRowsetBaseImpl<T, Storage, CreatorClass, ArrayType>,
  5890.     public IRowsetImpl<T>
  5891. {
  5892.     typedef CRowsetBaseImpl< T, Storage, CreatorClass, ArrayType> _RowsetBaseClass;
  5893.  
  5894. BEGIN_COM_MAP(CRowsetImpl)
  5895.     COM_INTERFACE_ENTRY(IRowset)
  5896.     COM_INTERFACE_ENTRY_CHAIN(_RowsetBaseClass)
  5897. END_COM_MAP()
  5898. };
  5899.  
  5900.  
  5901. class CTABLESRow
  5902. {
  5903. public:
  5904.  
  5905.     WCHAR m_szCatalog[129];
  5906.     WCHAR m_szSchema[129];
  5907.     WCHAR m_szTable[129];
  5908.     WCHAR m_szType[129];
  5909.     WCHAR m_szDesc[129];
  5910.     GUID  m_guid;
  5911.  
  5912.     CTABLESRow()
  5913.     {
  5914.         m_szCatalog[0] = NULL;
  5915.         m_szSchema[0] = NULL;
  5916.         m_szTable[0] = NULL;
  5917.         m_szType[0] = NULL;
  5918.         m_szDesc[0] = NULL;
  5919.         m_guid = GUID_NULL;
  5920.     }
  5921.  
  5922. BEGIN_PROVIDER_COLUMN_MAP(CTABLESRow)
  5923.     PROVIDER_COLUMN_ENTRY("TABLE_CATALOG", 1, m_szCatalog)
  5924.     PROVIDER_COLUMN_ENTRY("TABLE_SCHEMA", 2, m_szSchema)
  5925.     PROVIDER_COLUMN_ENTRY("TABLE_NAME", 3, m_szTable)
  5926.     PROVIDER_COLUMN_ENTRY("TABLE_TYPE", 4, m_szType)
  5927.     PROVIDER_COLUMN_ENTRY("TABLE_GUID", 5, m_guid)
  5928.     PROVIDER_COLUMN_ENTRY("DESCRIPTION", 6, m_szDesc)
  5929. END_PROVIDER_COLUMN_MAP()
  5930.  
  5931. };
  5932.  
  5933.  
  5934. class CCOLUMNSRow
  5935. {
  5936. public:
  5937.  
  5938.     WCHAR   m_szTableCatalog[129];
  5939.     WCHAR   m_szTableSchema[129];
  5940.     WCHAR   m_szTableName[129];
  5941.     WCHAR   m_szColumnName[129];
  5942.     GUID    m_guidColumn;
  5943.     ULONG   m_ulColumnPropID;
  5944.     ULONG   m_ulOrdinalPosition;
  5945.     VARIANT_BOOL    m_bColumnHasDefault;
  5946.     WCHAR   m_szColumnDefault[129];
  5947.     ULONG   m_ulColumnFlags;
  5948.     VARIANT_BOOL    m_bIsNullable;
  5949.     USHORT  m_nDataType;
  5950.     GUID    m_guidType;
  5951.     ULONG   m_ulCharMaxLength;
  5952.     ULONG   m_ulCharOctetLength;
  5953.     USHORT  m_nNumericPrecision;
  5954.     short   m_nNumericScale;
  5955.     ULONG   m_ulDateTimePrecision;
  5956.     WCHAR   m_szCharSetCatalog[129];
  5957.     WCHAR   m_szCharSetSchema[129];
  5958.     WCHAR   m_szCharSetName[129];
  5959.     WCHAR   m_szCollationCatalog[129];
  5960.     WCHAR   m_szCollationSchema[129];
  5961.     WCHAR   m_szCollationName[129];
  5962.     WCHAR   m_szDomainCatalog[129];
  5963.     WCHAR   m_szDomainSchema[129];
  5964.     WCHAR   m_szDomainName[129];
  5965.     WCHAR   m_szDescription[129];
  5966.  
  5967.     CCOLUMNSRow()
  5968.     {
  5969.         ClearMembers();
  5970.     }
  5971.  
  5972.     void ClearMembers()
  5973.     {
  5974.         m_szTableCatalog[0] = NULL;
  5975.         m_szTableSchema[0] = NULL;
  5976.         m_szTableName[0] = NULL;
  5977.         m_szColumnName[0] = NULL;
  5978.         m_guidColumn = GUID_NULL;
  5979.         m_ulColumnPropID = 0;
  5980.         m_ulOrdinalPosition = 0;
  5981.         m_bColumnHasDefault = VARIANT_FALSE;
  5982.         m_szColumnDefault[0] = NULL;
  5983.         m_ulColumnFlags = 0;
  5984.         m_bIsNullable = VARIANT_FALSE;
  5985.         m_nDataType = 0;
  5986.         m_guidType = GUID_NULL;
  5987.         m_ulCharMaxLength = 0;
  5988.         m_ulCharOctetLength = 0;
  5989.         m_nNumericPrecision = 0;
  5990.         m_nNumericScale = 0;
  5991.         m_ulDateTimePrecision = 0;
  5992.         m_szCharSetCatalog[0] = NULL;
  5993.         m_szCharSetSchema[0] = NULL;
  5994.         m_szCharSetName[0] = NULL;
  5995.         m_szCollationCatalog[0] = NULL;
  5996.         m_szCollationSchema[0] = NULL;
  5997.         m_szCollationName[0] = NULL;
  5998.         m_szDomainCatalog[0] = NULL;
  5999.         m_szDomainSchema[0] = NULL;
  6000.         m_szDomainName[0] = NULL;
  6001.         m_szDescription[0] = NULL;
  6002.     }
  6003.  
  6004.  
  6005. BEGIN_PROVIDER_COLUMN_MAP(CCOLUMNSRow)
  6006.     PROVIDER_COLUMN_ENTRY("TableCatalog", 1, m_szTableCatalog)
  6007.     PROVIDER_COLUMN_ENTRY("TableSchema", 2, m_szTableSchema)
  6008.     PROVIDER_COLUMN_ENTRY("TableName", 3, m_szTableName)
  6009.     PROVIDER_COLUMN_ENTRY("ColumnName", 4, m_szColumnName)
  6010.     PROVIDER_COLUMN_ENTRY("Column",5, m_guidColumn)
  6011.     PROVIDER_COLUMN_ENTRY("ColumnPropID",6, m_ulColumnPropID)
  6012.     PROVIDER_COLUMN_ENTRY("OrdinalPosition",7, m_ulOrdinalPosition)
  6013.     PROVIDER_COLUMN_ENTRY("ColumnHasDefault",8, m_bColumnHasDefault)
  6014.     PROVIDER_COLUMN_ENTRY("ColumnDefault",9, m_szColumnDefault)
  6015.     PROVIDER_COLUMN_ENTRY("ColumnFlags",10, m_ulColumnFlags)
  6016.     PROVIDER_COLUMN_ENTRY("IsNullable",11, m_bIsNullable)
  6017.     PROVIDER_COLUMN_ENTRY("DataType",12, m_nDataType)
  6018.     PROVIDER_COLUMN_ENTRY("Type",13, m_guidType)
  6019.     PROVIDER_COLUMN_ENTRY("CharMaxLength",14, m_ulCharMaxLength)
  6020.     PROVIDER_COLUMN_ENTRY("CharOctetLength",15, m_ulCharOctetLength)
  6021.     PROVIDER_COLUMN_ENTRY("NumericPrecision",16, m_nNumericPrecision)
  6022.     PROVIDER_COLUMN_ENTRY("NumericScale",17, m_nNumericScale)
  6023.     PROVIDER_COLUMN_ENTRY("DateTimePrecision",18, m_ulDateTimePrecision)
  6024.     PROVIDER_COLUMN_ENTRY("CharSetCatalog", 19, m_szCharSetCatalog)
  6025.     PROVIDER_COLUMN_ENTRY("CharSetSchema", 20, m_szCharSetSchema)
  6026.     PROVIDER_COLUMN_ENTRY("CharSetName", 21, m_szCharSetName)
  6027.     PROVIDER_COLUMN_ENTRY("CollationCatalog", 22, m_szCollationCatalog)
  6028.     PROVIDER_COLUMN_ENTRY("CollationSchema", 23, m_szCollationSchema)
  6029.     PROVIDER_COLUMN_ENTRY("CollationName", 24, m_szCollationName)
  6030.     PROVIDER_COLUMN_ENTRY("DomainCatalog", 25, m_szDomainCatalog)
  6031.     PROVIDER_COLUMN_ENTRY("DomainSchema", 26, m_szDomainSchema)
  6032.     PROVIDER_COLUMN_ENTRY("DomainName", 27, m_szDomainName)
  6033.     PROVIDER_COLUMN_ENTRY("Description", 28, m_szDescription)
  6034. END_PROVIDER_COLUMN_MAP()
  6035. };
  6036.  
  6037. template <class ArrayClass>
  6038. HRESULT InitFromRowset(ArrayClass& rgData, DBID* pTableID, DBID* pIndexID, IUnknown* pSession, LONG* pcRowsAffected)
  6039. {
  6040.     CComQIPtr<IOpenRowset> spOpenRowset = pSession;
  6041.     if (spOpenRowset == NULL)
  6042.         return E_FAIL;
  6043.     CComPtr<IColumnsInfo> spColInfo;
  6044.     HRESULT hr = spOpenRowset->OpenRowset(NULL, pTableID, pIndexID, IID_IColumnsInfo, 0, NULL, (IUnknown**)&spColInfo);
  6045.     if (FAILED(hr))
  6046.         return hr;
  6047.     LPOLESTR szColumns = NULL;
  6048.     ULONG cColumns = 0;
  6049.     DBCOLUMNINFO* pColInfo = NULL;
  6050.     hr = spColInfo->GetColumnInfo(&cColumns, &pColInfo, &szColumns);
  6051.     if (FAILED(hr))
  6052.         return hr;
  6053.     *pcRowsAffected = 0;
  6054.     for (ULONG iCol = 0; iCol < cColumns;  iCol++)
  6055.     {
  6056.         CCOLUMNSRow crData;
  6057.         DBCOLUMNINFO& rColCur = pColInfo[iCol];
  6058.         lstrcpynW(crData.m_szTableName, pTableID->uName.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szTableName));
  6059.         lstrcpynW(crData.m_szColumnName, rColCur.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szColumnName));
  6060.         lstrcpynW(crData.m_szDescription, rColCur.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szColumnName));
  6061.         GUID* pGuidCol = CDBIDOps::GetDBIDpGuid(rColCur.columnid);
  6062.         if (pGuidCol)
  6063.             crData.m_guidColumn = *pGuidCol;
  6064.         else
  6065.             crData.m_guidColumn = GUID_NULL;
  6066.         crData.m_ulColumnPropID = CDBIDOps::GetPropIDFromDBID(rColCur.columnid);
  6067.         crData.m_ulOrdinalPosition = rColCur.iOrdinal;
  6068.         crData.m_ulColumnFlags = rColCur.dwFlags;                    
  6069.         crData.m_bIsNullable = (rColCur.dwFlags & DBCOLUMNFLAGS_ISNULLABLE) ? VARIANT_TRUE : VARIANT_FALSE;
  6070.         crData.m_nDataType = rColCur.wType;
  6071.         crData.m_ulCharMaxLength = rColCur.ulColumnSize;
  6072.         crData.m_nNumericPrecision = rColCur.bPrecision;
  6073.         crData.m_nNumericScale = rColCur.bScale;
  6074.         if (!rgData.Add(crData))
  6075.         {
  6076.             CoTaskMemFree(pColInfo);
  6077.             CoTaskMemFree(szColumns);
  6078.             return E_OUTOFMEMORY;
  6079.         }
  6080.         *pcRowsAffected++;
  6081.     }
  6082.  
  6083.     CoTaskMemFree(pColInfo);
  6084.     CoTaskMemFree(szColumns);
  6085.     return S_OK;
  6086. }
  6087.  
  6088. class CPROVIDER_TYPERow
  6089. {
  6090. public:
  6091. // Attributes
  6092.     WCHAR           m_szName[129];
  6093.     USHORT          m_nType;
  6094.     ULONG           m_ulSize;
  6095.     WCHAR           m_szPrefix[129];
  6096.     WCHAR           m_szSuffix[129];
  6097.     WCHAR           m_szCreateParams[129];
  6098.     VARIANT_BOOL    m_bIsNullable;
  6099.     VARIANT_BOOL    m_bCaseSensitive;
  6100.     VARIANT_BOOL    m_bSearchable;
  6101.     VARIANT_BOOL    m_bUnsignedAttribute;
  6102.     VARIANT_BOOL    m_bFixedPrecScale;
  6103.     VARIANT_BOOL    m_bAutoUniqueValue;
  6104.     WCHAR           m_szLocalTypeName[129];
  6105.     short           m_nMinScale;
  6106.     short           m_nMaxScale;
  6107.     GUID            m_guidType;
  6108.     WCHAR           m_szTypeLib[129];
  6109.     WCHAR           m_szVersion[129];
  6110.     VARIANT_BOOL    m_bIsLong;
  6111.     VARIANT_BOOL    m_bBestMatch;
  6112.  
  6113.     CPROVIDER_TYPERow()
  6114.     {
  6115.         m_szName[0] = NULL;
  6116.         m_nType = 0;
  6117.         m_ulSize = 0;
  6118.         m_szPrefix[0] = NULL;
  6119.         m_szSuffix[0] = NULL;
  6120.         m_szCreateParams[0] = NULL;
  6121.         m_bIsNullable = VARIANT_FALSE;
  6122.         m_bCaseSensitive = VARIANT_FALSE;
  6123.         m_bSearchable = VARIANT_FALSE;
  6124.         m_bUnsignedAttribute = VARIANT_FALSE;
  6125.         m_bFixedPrecScale = VARIANT_FALSE;
  6126.         m_bAutoUniqueValue = VARIANT_FALSE;
  6127.         m_szLocalTypeName[0] = NULL;
  6128.         m_nMinScale = 0;
  6129.         m_nMaxScale = 0;
  6130.         m_guidType = GUID_NULL;
  6131.         m_szTypeLib[0] = NULL;
  6132.         m_szVersion[0] = NULL;
  6133.         m_bIsLong = VARIANT_FALSE;
  6134.         m_bBestMatch = VARIANT_FALSE;
  6135.     }
  6136. // Binding Maps
  6137. BEGIN_PROVIDER_COLUMN_MAP(CPROVIDER_TYPERow)
  6138.     PROVIDER_COLUMN_ENTRY("Name", 1, m_szName)
  6139.     PROVIDER_COLUMN_ENTRY("Type", 2, m_nType)
  6140.     PROVIDER_COLUMN_ENTRY("Size", 3, m_ulSize)
  6141.     PROVIDER_COLUMN_ENTRY("Prefix", 4, m_szPrefix)
  6142.     PROVIDER_COLUMN_ENTRY("Suffix", 5, m_szSuffix)
  6143.     PROVIDER_COLUMN_ENTRY("CreateParams", 6, m_szCreateParams)
  6144.     PROVIDER_COLUMN_ENTRY("IsNullable", 7, m_bIsNullable)
  6145.     PROVIDER_COLUMN_ENTRY("CaseSensitive", 8, m_bCaseSensitive)
  6146.     PROVIDER_COLUMN_ENTRY("Searchable", 9, m_bSearchable)
  6147.     PROVIDER_COLUMN_ENTRY("UnsignedAttribute", 10, ,m_bUnsignedAttribute)
  6148.     PROVIDER_COLUMN_ENTRY("FixedPrecScale", 11, m_bFixedPrecScale)
  6149.     PROVIDER_COLUMN_ENTRY("AutoUniqueValue", 12, m_bAutoUniqueValue)
  6150.     PROVIDER_COLUMN_ENTRY("LocalTypeName", 13, m_szLocalTypeName)
  6151.     PROVIDER_COLUMN_ENTRY("MinScale", 14, m_nMinScale)
  6152.     PROVIDER_COLUMN_ENTRY("MaxScale", 15, m_nMaxScale)
  6153.     PROVIDER_COLUMN_ENTRY("GUID Type", 16, m_guidType)
  6154.     PROVIDER_COLUMN_ENTRY("TypeLib", 17, m_szTypeLib)
  6155.     PROVIDER_COLUMN_ENTRY("Version", 18, m_szVersion)
  6156.     PROVIDER_COLUMN_ENTRY("IsLong", 19, m_bIsLong)
  6157.     PROVIDER_COLUMN_ENTRY("BestMatch", 20, m_bBestMatch)
  6158. END_PROVIDER_COLUMN_MAP()
  6159. };
  6160.  
  6161.  
  6162. class CEnumRowsetImpl
  6163. {
  6164. public:
  6165.  
  6166.     WCHAR m_szSourcesName[256];
  6167.     WCHAR m_szSourcesParseName[256];
  6168.     WCHAR m_szSourcesDescription[256];
  6169.     unsigned short m_iType;
  6170.     VARIANT_BOOL m_bIsParent;
  6171.  
  6172. BEGIN_PROVIDER_COLUMN_MAP(CEnumRowsetImpl)
  6173.     PROVIDER_COLUMN_ENTRY("SOURCES_NAME", 1, m_szSourcesName)
  6174.     PROVIDER_COLUMN_ENTRY("SOURCES_PARSENAME", 2, m_szSourcesParseName)
  6175.     PROVIDER_COLUMN_ENTRY("SOURCES_DESCRIPTION", 3, m_szSourcesDescription)
  6176.     PROVIDER_COLUMN_ENTRY("SOURCES_TYPE", 4, m_iType)
  6177.     PROVIDER_COLUMN_ENTRY("SOURCES_ISPARENT", 5, m_bIsParent)
  6178. END_PROVIDER_COLUMN_MAP()
  6179.  
  6180. };
  6181.  
  6182. #endif
  6183.